Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a fully applied curried function thunk in Haskell?

Tags:

haskell

Or put it another way:

Can I apply all arguments to a curried function without evaluating it? So I would have a function value still, and not the result of the computation?

Example:

add x y = x + y
add1 = add 3   {- add1 is a function -}
add2 = add1 4  {- add2 is 7, but I would like to have a function 
                  I can call with no arguments!? -}

The reason is to pass functions around that are fully bound and can be called in arbitrary situations and without the need to provide additional arguments.

No tricks please (like providing a bogus last argument like 1 or True at the call site).

like image 483
ThomasH Avatar asked Dec 25 '22 14:12

ThomasH


1 Answers

A function always takes an argument. That which does not take an argument is not a function. The only little trickery here is that some things Haskell considers values are, in System FC, functions. For instance 7 has type Num a => a, meaning that in Haskell it's a polymorphic number, but in System FC it's a function that takes a Num a dictionary and produces an a. So you kind of can have what you asked for.

However, what you asked for does not seem to be what you want! The fact that a computation is expensive does not mean you should make it the result of a function

x = really expensive computation

doesn't actually calculate x. Only when you inspect the value of x (by pattern matching, or seq, or evaluate, etc.) does x get evaluated, and even then it is only evaluated as far as necessary.

Comment:

Ok, so GHCi betrayed me into believing that add1 4 is immediatly evaluated to 7, and this would not be the case in a normal program run?!

Nope! You typed add1 4 at the GHCi prompt. GHCi therefore concluded that you wanted it to print that value. In order to print a number, all of the digits need to be calculated, and the number itself needs to be calculated first! If you want to peer under the hood, you can use GHCi's :print or :sprint commands, which let you inspect unevaluated or partially evaluated things.

Prelude> let foo = (1+2, 3+4) :: (Int, Int)
Prelude> :print foo
foo = ((_t3::Int),(_t4::Int))
Prelude> fst foo
3
Prelude> :print foo
foo = (3,(_t5::Int))
Prelude> snd foo
7
Prelude> :print foo
foo = (3,7)

Note: delaying things lazily has potentially bad performance implications. GHC goes to great lengths in compiled code to figure out when it can make them strict instead without affecting the meaning of the program and without causing other performance problems. This compiler pass is called "demand analysis", and it's a particular form of "strictness analysis".

like image 138
dfeuer Avatar answered Feb 02 '23 01:02

dfeuer