Surprising difference between lambda and partial application
This results in f initialized with a lambda that calls say once, followed by a call to say "ho" that is executed when this is run
> ./build//bin/fz -e 'f ()->unit := say "hi"; say "ho"'
ho
>
while this results in f initialized with a lambda that calls say twice and no calls to say being executed:
> ./build//bin/fz -e 'f ()->unit := ()->say "hi"; say "hi"'
>
Would be nice to avoid this surprise...
This is related to #2370 and #2251.
Thought about this a bit and came to the conclusion that the second case
> ./build//bin/fz -e 'f ()->unit := ()->say "hi"; say "hi"'
is ambiguous since it is unclear if the semicolon terminates the block/exprs in the lambda or the block/exprs consisting of`` the f ()->unit := ()->say "hi"; say "hi".
We have the same problem with nested ifs:
> ./build//bin/fz -e "if true then if false then say 1; say 2"
which could be parsed as
> ./build//bin/fz`` -e "{ if true then if false then say 1 }; say 2"
or as
> ./build//bin/fz`` -e "if true then { if false then { say 1 }; say 2 }"
or as
> ./build//bin/fz`` -e "if true then if false then { say 1; say 2 }"
The solution IMHO is to produce an error in this case and suggest using braces to disambiguate the code. So, ideally, I would like to see
> ./build//bin/fz -e 'f ()->unit := ()->say "hi"; say "hi"'
command line:1:26: error 1: Ambiguous semicolon in nested blocks
f ()->unit := ()->say "hi"; say "hi"
---------------------------^
It is unclear whether this semicolon terminates the inner block or not.
To solve this, add braces { } as follows
f ()->unit := ()->{ say "hi"; say "hi" }
or
f ()->unit := ()->{ say `"hi"}; say "hi"
one error.
And a similar message for the nested if example.
This is a variant of the dangling else problem, which we also have and should solve similarly by producing an error.
@fridis What about the first case, should the behavior stay as it is (printing ho)?
f ()->unit := say "hi"; say "ho"
And what should happen in the following cases?
public log(s T) => say s; s
public peek (f T -> unit) =>
as_list ? nil =>
| c Cons => f c.head; _ := c.tail.peek f
as_list
the first case f ()->unit := say "hi"; say "ho" should be a sequence of two exprs, an assignment followed by the call say "ho", it should print ho when executed.
The second should best trigger an error similar to the lambda case, and offer the alternatives public log(s T) => { say s }; s or public log(s T) => { say s; s } to disambiguate the code.
That third case is fine, there are not nested blocks within a single line, so this is not ambiguous.