As we all know, let expression is actually just a syntactic sugar for immediately invoked lambda expression (IILA). Actually not entirely correct, as pointed out in this comment.
For example, in Haskell:
let x = a in bis the same as
(\x -> b) a In the quest of minimising syntax, we can remove let expression, but it's obviously bad for UX because IILA is unreadable.
So why not the other way round, remove lambda expression and replace it with extended let expression?
Let's see.
Lambda abstraction:
\x -> bcan be written as let-expression that is not instantiated with any value:
let x; bAnd so:
\x -> \y -> bis equivalent to:
let x; let y; bApplication in extended let-expression is equivalent to lambda. For example in lambda:
(\x -> b) acan be written as follows in let-expression:
(let x; b) aSince Haskell does not have a built-in mechanism to define argument's default value, we can still achieve the same effect with the used of Maybe type.
sayHello :: Maybe Int -> [String]
sayHello (Just count) = replicate count "Hello"
sayHello None = ["Hello"]In this case it's acceptable to pass in None explicitly, but in case where we have a lot of arguments with default values, the call-site will become cluttered with noise.
In extended let-expression, we can easily introduce a keyword, say overridable to allow arguments with default values.
For example,
sayHello =
let overridable count = 1;
replicate count "Hello"
sayHello -- ["Hello"]
sayHello 2 -- ["Hello", "Hello"]But of course, overridable arguments must only appear after all mandatory arguments.
As we can see above, with one simple extension to let-expression, we can completely eliminate the necessity of the lambda syntax.
Namely the uninstantiated let-expression, let var: type; which allow us to introduce function abstraction.
Also, we can see that by simply introducing a minimal syntax, say the overridable keyword, we can allow function argument's default value without cluttering the language grammar.
From the UX perspective, the implication of using extended let-expression to replace lambda syntax is the reduction of choice, which can ultimately leads to better experience.
And hopefully, from the point of view of programming language designers, this kind of syntactical unification can be useful for those looking to minimise their language grammar.
let rec factorial =
let x: int;
if x <= 1 then
1
else
x * factorial (x - 1)let average =
let xs: int list;
let sum = fold (let acc; let x; acc + x) 0 xs;
sum / length xs
Then I also realised that this idea can be further extended to support a
do-notationlike syntax, for example:Can be translated as: