Replies: 2 comments 5 replies
-
A form like this in S-Expression notation: (for/foldr ([acc '()] #:delay)
([v (in-range 1 4)])
(printf "--> ~v\n" v)
(begin0
(cons v (force acc))
(printf "<-- ~v\n" v))) Would be written like this in the current version of Wraith: for/foldr [acc '() & #:delay]
[v (in-range 1 4)]
printf "--> ~v\n" v
begin0
cons v (force acc)
printf "<-- ~v\n" v And this Wraith version works as-is without having to define a new By contrast Shrubbery-Rhombus macros need to be written specifically for Shrubbery... If I were to define a macro in Shrubbery to do this it might look something like this: for_foldr ((acc: [], ~delay),
(v: in_range(1, 4))):
printf("--> ~v\n", v)
begin0:
cons(v, force(acc))
printf("<-- ~v\n", v) Which needs an extra grouping of parens that Racket's If I changed the lexer for identifiers and relaxed the indentation and for/foldr (acc: [], ~delay)
(v: in-range(1, 4)):
printf("--> ~v\n", v)
begin0:
cons(v, force(acc))
printf("<-- ~v\n", v) Which would be consistent with a possible bridge to S-Expression notation that parsed to the same tree as the original Racket and Wraith examples. |
Beta Was this translation helpful? Give feedback.
-
Here's something I've been experimenting with in https://github.com/mflatt/rhombus-prototype/tree/for (just a partial implementation, no documentation). It's related to @rocketnia's "streams are declared as part of a block". In the example below,
In this example, A "folder" can appear after
Similarly,
You could imagine a These Meanwhile, an advantage of putting element bindings in the body is that no special syntax like
The current experiment doesn't yet have The current experiment also doesn't quite parse in the right way, because it's too eager about expanding the right-hand side of I'm not sure about using a keyword for |
Beta Was this translation helpful? Give feedback.
-
In today's Rhombus meeting,
for/fold
came up as a particular place where Shrubbery notation might be lacking. I mentioned that it was like a form of primitive recursion.Primitive recursion is a limited kind of recursion where the recursion must proceed on a smaller structure than the input. It's used in total functional languages to guarantee that recursive operations over inductive data types terminate. Nowadays, languages like Agda can figure out the termination guarantees a lot more kinds of recursion, and users don't have to specify what "input" they're recursing over like they do when they use primitive recursion directly.
Primitive recursion over a cons list is
foldr
. Its inputs, in some order, are:car
) and a state (the result of recursion over the list in thecdr
) and returns a state.And the result is:
This isn't exactly the signature of Racket's
foldr
, but it's easy to implement something like this in terms of Racket'sfoldr
and vice versa.Anyhow, if we want to make a syntax that has a handler for nil and a handler for cons, I think it could look similar to a
match
form.Here's an example of
for/foldr
in the docs:Apologies for how unfamliiar I am with the Rhombus prototype, but I imagine something shaped roughly like this pseudocode could work:
And for
for/fold
rather thanfor/foldr
, we would be doing primitive recursion over a snoc list rather than a cons list:(Putting
values(...)
in the argument of another pattern might be suspect. That's one of many things that makes this pseudocode.... 😅 )Another option here could be to make these folding styles more integrated into
match
by having a specialrecur
pattern...I realize none of these are very
for
-like, since the variables aren't close to the expressions that produce them (v
andin_range(1, 4)
;acc
and the branch results;i
and[1, 2, 3, 4]
; andvalues(sum, rev_roots)
and the branch results). Afor
form probably doesn't need to have the verbosity ofStreamNil
,StreamCons
,StreamLin
, andStreamSnoc
either, sincefor
forms are specialized to streams.So, another option could be something more like this, where the variables
v
andi
are brought closer to the streams producing them and the variablesacc
andvalues(sum, rev_roots)
are brought into the header so they can apply to both branch results:These examples only have one stream each. To accommodate multiple streams, it might help to adjust the syntax so the streams are declared as part of a block. So here's yet another possible take on things:
These are just some possible ideas on my mind. Feel free to take this thread wherever you like.
I searched around for some existing discussion on this but didn't quite find any. I'm aware of https://github.com/samdphillips/rhombus-examples but not really aware of where everyone else is keeping their Rhombus prototype experiments, so I might have overlooked some obvious
for/fold
tinkering that's already been going on somewhere.Beta Was this translation helpful? Give feedback.
All reactions