So I'm still shoring up a new bootstrap executable, patching around in a 6-years-out-of-date codebase. It's in some ways a cruel and unusual punishment... but in other ways a good trip down memory lane to revisit decisions that were made, and ask "was that the right decision?"
The 6-year-old EXE defined an enfix form of lambda as =>
. I shifted it to the lighter form as ->
. Contrast:
y: case [
1 > 2 [<no>]
1 < 2 [<yes>]
] then (lambda [x] [
assert [x = <yes>]
1000 + 20
])
assert [y = 1020]
y: case [
1 > 2 [<no>]
1 < 2 [<yes>]
] then x => [
assert [x = <yes>]
1000 + 20
]
assert [y = 1020]
y: case [
1 > 2 [<no>]
1 < 2 [<yes>]
] then x -> [
assert [x = <yes>]
1000 + 20
]
assert [y = 1020]
(Supplemental: Reddit post on "What's the syntax of lambda expressions in your language")
I like the ->
and don't think there's a greater purpose for it in the box. As with everything else, overriding it is a personal choice.
A Speaking-With-Tics Note
Mechanically getting this to work is non-trivial:
The Most Vexing Evaluation: LAMBDA meets THEN/ELSE
Part of what makes it non-trivial is the "literal lookback" by which ->
infixedly snatches the X without letting it evaluate.
@bradrn might argue such mechanics shouldn't be necessary, because source-level non-evaluation should be explicit, e.g. 'x -> [...]
y: case [
1 > 2 [<no>]
1 < 2 [<yes>]
] then 'x -> [
assert [x = <yes>]
1000 + 20
]
assert [y = 1020]
But that's one more stroke of key than I want, and one more piece of dirt than I want to see. I know from context that slot is a variable name, in the most common case. I'm not upset by intricate work to faciliate it, if it actually works (and empowers other creative things). So I need to see hard disproofs before sacrificing what I consider to be "the point" of the design.
I'm always ready to look at it from a further perspective to see a "greater point". But still--from where I stand--that apostrophe sucks relative to not having it. (And if you read the details of the implementation post, the only reason it's allowed to work in a quoted slot is because of left literalism, so...)
What About Multiple Arguments?
Notationally there are questions about this form of lambda. Does it use a block for multiple arguments?
>> foo: [a b] -> [a + b + 20]
>> foo 400 600
== 1020
It could, but you could be weirder:
foo: a.b -> [a + b + 20]
foo: a/b -> [a + b + 20]
This would look a little tighter with branching, I think, since it wouldn't compete with the branches:
case [
...
] then [a b] -> [
...
]
case [
...
] then a.b -> [
...
]
But wait, you'd never use it with a branch... because a branch only produces one value.
UNLESS... what if what this form of lambda did was unpack packs?
case [
true [pack [10 + 20, 3 + 4]] ; makes antiform ~['30 '7]~
...
] then [a b] -> [
assert [a = 30, b = 7]
]
case [
true [pack [10 + 20, 3 + 4]]
...
] then a -> [
assert [a = 30]
]
So I've been thinking this is what it should actually do. It means -> won't be a good way to define functions or lambdas generally, but you have FUNC(TION) and LAMBDA for that.
I don't know that enabling a lighter notation like a.b
or a/b
is worth it.
case [
true [pack [10 + 20, 3 + 4]]
...
] then a.b -> [
assert [a = 30, b = 7]
]
case [
true [pack [10 + 20, 3 + 4]]
...
] then a/b -> [
assert [a = 30, b = 7]
]
Maybe just confusing, and limits what you can put in the spec. Easier to add later if it seems useful than put it in now and take out later.
Is There A Good Name For "Lambda Lite"?
We could call it an "unpacking lambda". Maybe it's controlled with a refinement:
>> foo: lambda/unpack [a b] [a + b + 20]
>> foo pack [400 600]
== 1020
Then ->: :lambda/unpack
We could just call it "an unpacker".
>> foo: unpacker [a b] [a + b + 20]
>> foo pack [400 600]
== 1020
Then ->: :unpacker
The problem with calling it an "unpacker" is that 9 (or more) times out of 10 it will only take a single argument and not unpack anything. So it seems better to classify it as a shade of distinction on lambda, but still when you point to an ->
on the screen say "then it passes the argument to the lambda..."