Lambda Expressions Without Parameters in Haskell and Lambda Calculus

haskelllambdalambda-calculuspythonscheme

In eager languages like Scheme and Python, you can use a lambda expression without parameters to delay evaluation, e.g. in Scheme (Chicken Scheme):

#;1> (define (make-thunk x) (lambda () (+ x 1)))
#;2> (define t (make-thunk 1))
#;3> (t)
2

In line 2, t is bound to the unevaluated expression (lambda () (+ 1 1)), which is then evaluated to 2 in line 3.

Similarly, in Python:

>>> def make_thunk(x): return lambda: x + 1
... 
>>> t = make_thunk(1)
>>> t()
2

Using this technique one can implement lazy evaluation in an eager language.

So, I was expecting that Haskell would not have lambda expressions without parameters because the language is already lazy and there is no need to build delayed expressions. To my surprise, I found out that in Haskell it is possible to write the lambda expression

\() -> "s"

which can only be applied to the () value like so:

(\() -> "s") ()

giving the result

"s"

Applying this function to any argument other than () throws an exception (at least as far as I could see during my tests). This seems different from delayed evaluation in Scheme and Python, because the expression still needs an argument to be evaluated.
So what does a lambda expression without variables (like \() -> "s") mean in Haskell and what can it be useful for?

Also, I would be curious to know if similar parameterless lambda expressions exist in (some variety of) lambda-calculus.

Best Answer

Well, the other answers cover what \() -> "something" means in Haskell: an unary function that takes () as argument.

  • What is a function without arguments? – A value. Actually, it can occasionally be useful to think of variables as nullary functions that evaluate to their value. The let-syntax for a function without arguments (which doesn't actually exist) ends up giving you a variable binding: let x = 42 in ...

  • Does lambda calculus have nullary functions? – No. Every function takes exactly one argument. However, this argument may be a list, or the function may return another function that takes the next argument. Haskell prefers the latter solution, so that a b c is actually two function calls ((a b) c). To simulate nullary functions, you have to pass some unused placeholder value.