I was writing a small file browser in Flapjax and have encountered a problem with tagRec: there seems to be no way to make one dynamically created tag to depend on another dynamically created tag's events.
What I would like to achieve is a tree with branches that can be shown or hidden.
The tree (or rather, a forest) for testing is the parse tree of an expression a + b * c, which is translated to JS as follows:
> I was writing a small file browser in Flapjax and have encountered > a problem with tagRec: there seems to be no way to make one > dynamically created tag to depend on another dynamically created > tag's events.
> What I would like to achieve is a tree with branches that > can be shown or hidden.
> The tree (or rather, a forest) for testing is the parse tree of an expression > a + b * c, which is translated to JS as follows:
Looking at your solution, you didn't actually need a generalized
tagRec since you had a 1-way dependency. However, there are cases
when you want a pair of tags to depend on events from each other. For
that, a generalized tagRec would be great.
Maybe one of the implementors will add it out soon.
> 2009/6/4 Artyom Shalkhakov <artyom.shalkha...@gmail.com>:
>> I was writing a small file browser in Flapjax and have encountered
>> a problem with tagRec: there seems to be no way to make one
>> dynamically created tag to depend on another dynamically created
>> tag's events.
>> What I would like to achieve is a tree with branches that
>> can be shown or hidden.
>> The tree (or rather, a forest) for testing is the parse tree of an expression
>> a + b * c, which is translated to JS as follows:
I made a construct called rec_e for similar tasks in Continue/Resume:
rec_e :: (Event A -> Event A) -> Event A
It takes a function from events to events, and calls it in such a way that the
event stream it returns and the event stream it takes are "the same"
(naturally, they aren't actually the same, they just fire at the same time).
Then it also returns this event stream. It can be defined thus:
function rec_e(fn) {
var inE = receiver_e();
var outE = fn(inE);
outE.transform_e(function(_) {
inE.sendEvent(_);
});
return outE;
}
On 6/5/09, Arjun Guha <arjun.g...@gmail.com> wrote:
> Looking at your solution, you didn't actually need a generalized
> tagRec since you had a 1-way dependency. However, there are cases
> when you want a pair of tags to depend on events from each other. For
> that, a generalized tagRec would be great.
> Maybe one of the implementors will add it out soon.
> Arjun
> On Fri, Jun 5, 2009 at 07:53, Artyom Shalkhakov
> <artyom.shalkha...@gmail.com> wrote:
>> 2009/6/4 Artyom Shalkhakov <artyom.shalkha...@gmail.com>:
>>> I was writing a small file browser in Flapjax and have encountered
>>> a problem with tagRec: there seems to be no way to make one
>>> dynamically created tag to depend on another dynamically created
>>> tag's events.
>>> What I would like to achieve is a tree with branches that
>>> can be shown or hidden.
>>> The tree (or rather, a forest) for testing is the parse tree of an
>>> expression
>>> a + b * c, which is translated to JS as follows:
> Looking at your solution, you didn't actually need a generalized > tagRec since you had a 1-way dependency. However, there are cases > when you want a pair of tags to depend on events from each other. For > that, a generalized tagRec would be great.
I have found a simple example where you need a generalized tagRec. (Actually, I need to solve this problem to continue with my current project.)
Let's say we have two links (buttons, tabs...) "A" and "B" and we want one of them to be "focused" (or "selected"). Focusing a link, as well as "unfocusing" it, should change it's color accordingly.
If we had Scheme's letrec in JS, the solution would look as follows:
> letrec a = A({href:'#', style:{color: > startsWith(mergeE(ev1.constantE('#777'), > ev2.constantE('#000')), > '#000')}}, "this is A") > b = A({href:'#', style:{color: > startsWith(mergeE(ev1.constantE('#000'), > ev2.constantE('#777')), > '#000')}}, "this is B") > ev1 = clicksE(a) > ev2 = clicksE(b) > in UL(LI(a),LI(b))
How to do this in JS? The best solution I found involves tricky assignments and effectful event streams.
I don't get how a menu (either hierarchical or not), a tabbed navigation, etc. could be implemented without such cyclic dependencies. We could do it imperatively, of course...
> Maybe one of the implementors will add it out soon.
> I made a construct called rec_e for similar tasks in Continue/Resume:
> rec_e :: (Event A -> Event A) -> Event A
> It takes a function from events to events, and calls it in such a way that the
> event stream it returns and the event stream it takes are "the same"
> (naturally, they aren't actually the same, they just fire at the same time).
> Then it also returns this event stream. It can be defined thus:
> function rec_e(fn) {
> var inE = receiver_e();
> var outE = fn(inE);
> outE.transform_e(function(_) {
> inE.sendEvent(_);
> });
> return outE;
> }
> On 6/5/09, Arjun Guha <arjun.g...@gmail.com> wrote:
>> Looking at your solution, you didn't actually need a generalized
>> tagRec since you had a 1-way dependency. However, there are cases
>> when you want a pair of tags to depend on events from each other. For
>> that, a generalized tagRec would be great.
>> Maybe one of the implementors will add it out soon.
>> Arjun
>> On Fri, Jun 5, 2009 at 07:53, Artyom Shalkhakov
>> <artyom.shalkha...@gmail.com> wrote:
>>> 2009/6/4 Artyom Shalkhakov <artyom.shalkha...@gmail.com>:
>>>> I was writing a small file browser in Flapjax and have encountered
>>>> a problem with tagRec: there seems to be no way to make one
>>>> dynamically created tag to depend on another dynamically created
>>>> tag's events.
>>>> What I would like to achieve is a tree with branches that
>>>> can be shown or hidden.
>>>> The tree (or rather, a forest) for testing is the parse tree of an
>>>> expression
>>>> a + b * c, which is translated to JS as follows:
> That's cool, but I couldn't adapt it to the problem at hand. Care
> to elaborate?
Sure. Rather than:
> letrec a = A({href:'#', style:{color:
> startsWith(mergeE(ev1.constantE('#777'),
> ev2.constantE('#000')),
> '#000')}}, "this is A")
> b = A({href:'#', style:{color:
> startsWith(mergeE(ev1.constantE('#000'),
> ev2.constantE('#777')),
> '#000')}}, "this is B")
> ev1 = clicksE(a)
> ev2 = clicksE(b)
> in UL(LI(a),LI(b))
Just do:
var list = null;
rec_e(function(clicks) {
var b_clicks = clicks.transform_e(
function(_) { return _ == '#000' ? '#777' : '#000'; });
var a = A({href:'#', style:{color: clicks.startsWith('#000')},
'this is A');
var b = A({href:'#', style:{color: b_clicks.startsWith('#000')},
'this is B');
list = UL(LI(a),LI(b));
return merge_e(clicksE(a).constant_e('#777'),
clicksE(b).constant_e('#000'));
});
The basic idea is that it's easy to write down the event stream you want at
the end of a function. We just need to get it back to the beginning of the
function and you can do anything you want. So that's what rec_e does--it takes
an event stream from the end of the function and feeds it back in at the
start.
Looking at this example, there's probably a more useful signature that would
let you return both the event stream you want to pass back and also another
return value (that becomes the return value of rec_e). That way, you could
just do
> 2009/6/5 Jacob Baskin <goingo...@gmail.com>:
> > I made a construct called rec_e for similar tasks in Continue/Resume:
> > rec_e :: (Event A -> Event A) -> Event A
> > It takes a function from events to events, and calls it in such a way
> > that the event stream it returns and the event stream it takes are "the
> > same" (naturally, they aren't actually the same, they just fire at the
> > same time). Then it also returns this event stream. It can be defined
> > thus:
> > function rec_e(fn) {
> > var inE = receiver_e();
> > var outE = fn(inE);
> > outE.transform_e(function(_) {
> > inE.sendEvent(_);
> > });
> > return outE;
> > }
> > On 6/5/09, Arjun Guha <arjun.g...@gmail.com> wrote:
> >> Looking at your solution, you didn't actually need a generalized
> >> tagRec since you had a 1-way dependency. However, there are cases
> >> when you want a pair of tags to depend on events from each other. For
> >> that, a generalized tagRec would be great.
> >> Maybe one of the implementors will add it out soon.
> >> Arjun
> >> On Fri, Jun 5, 2009 at 07:53, Artyom Shalkhakov
> >> <artyom.shalkha...@gmail.com> wrote:
> >>> 2009/6/4 Artyom Shalkhakov <artyom.shalkha...@gmail.com>:
> >>>> I was writing a small file browser in Flapjax and have encountered
> >>>> a problem with tagRec: there seems to be no way to make one
> >>>> dynamically created tag to depend on another dynamically created
> >>>> tag's events.
> >>>> What I would like to achieve is a tree with branches that
> >>>> can be shown or hidden.
> >>>> The tree (or rather, a forest) for testing is the parse tree of an
> >>>> expression
> >>>> a + b * c, which is translated to JS as follows:
> >>>>> [{label: 'plus', children: [
> >>>>> {label: 'a', children: []},
> >>>>> {label: 'multiply', children: [
> >>>>> {label: 'b',children: []},
> >>>>> {label: 'c',children: []}]}]}]
> >>>> Here's how it is converted to HTML:
> >>>>> // fun :: Forest * Maybe Hash -> Dom
> >>>>> function fun(y,vis) {
> >>>>> return UL(vis || {}, map(function(x) {
> >>>>> return tagRec(['click'],
> >>>>> function(e) {
> >>>>> var db =
> >>>>> toggleE('block','none',e).startsWith('block'); return
> >>>>> LI(A({href:'#'+x.label},x.label),
> >>>>> fun(x.children, {style: {display:
> >>>>> db}}));
> >>>>> });
> >>>>> }, y));
> >>>>> }
> >>> Suddenly I've found a solution which works okay and is still very nice.
> >>> Here it is:
> >>>> function fun(y,vis) {
> >>>> return UL(vis || {}, map(function(x) {
> >>>> var a = A({href:'#'+x.label},x.label);
> >>>> var db = toggleE('block','none',clicksE(a)).startsWith('block');
> >>>> return LI(a, fun(x.children,{style:{display:db}}));
> >>>> }, y));
> >>>> }
> >>> Strangely enough I got it working without any debugging at all, woot!
> >>> :)