HeinrichApfelmus / threepenny-gui

GUI framework that uses the web browser as a display.
https://heinrichapfelmus.github.io/threepenny-gui/
Other
439 stars 77 forks source link

sinking Element attributes #92

Closed int3 closed 10 years ago

int3 commented 10 years ago

Right now it is awkward to directly invoke sink on the children attribute, because sink children expects an argument of type Behavior [Element], but every Element constructor returns elements wrapped in the UI monad, so I've ended up with lots of values of the type Behavior (UI [Element]).

I ended up writing a function to 'bind' such attributes to the UI monad, like so:

bindAttr :: ReadWriteAttr a a1 o -> ReadWriteAttr a (UI a1) o
bindAttr a = mkReadWriteAttr (get' a) (flip $ (=<<) . flip (set' a))

Do you think this is a useful helper function, or should the API be extended in some other way?

HeinrichApfelmus commented 10 years ago

Actually, using sink on a Behavior (UI a) is semantically unsound. The question is: How often is the enclosed UI action executed in order to assign the value of type a? (Remember that UI actions may have side effects.) Behaviors are supposed to be continuous, i.e. there is no way to know how "often" a Behavior "updates" and hence no way to figure out how when the side effects are to be executed. (This is a design decision: Code that does not depend on the frequency of updates is easier to reason about.)

The bindAttr is more imperative in style, and hence doesn't have this problem. Still, I would prefer not to add it in order to discourage use with Behavior (UI a).

int3 commented 10 years ago

Ah, I see. Thanks for the explanation!