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" vAnd 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.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
In today's Rhombus meeting,
for/foldcame 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'sfoldrand 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
matchform.Here's an example of
for/foldrin 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/foldrather thanfor/foldr, we would be doing primitive recursion over a snoc list rather than a cons list:> (for/fold ([sum 0] [rev-roots null]) ([i '(1 2 3 4)]) (values (+ sum i) (cons (sqrt i) rev-roots))) 10 '(2 1.7320508075688772 1.4142135623730951 1)(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
matchby having a specialrecurpattern...I realize none of these are very
for-like, since the variables aren't close to the expressions that produce them (vandin_range(1, 4);accand the branch results;iand[1, 2, 3, 4]; andvalues(sum, rev_roots)and the branch results). Aforform probably doesn't need to have the verbosity ofStreamNil,StreamCons,StreamLin, andStreamSnoceither, sinceforforms are specialized to streams.So, another option could be something more like this, where the variables
vandiare brought closer to the streams producing them and the variablesaccandvalues(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/foldtinkering that's already been going on somewhere.Beta Was this translation helpful? Give feedback.
All reactions