Benboy
Benboy

Reputation: 353

When are F# function calls evaluated; lazily or immediately?

Curried functions in F#. I get the bit where passing in a subset of parameters yields a function with presets. I just wondered if passing all of the parameters is any different. For example:

let addTwo x y = x + y
let incr a = addTwo 1
let added = addTwo 2 2

incr is a function taking one argument. Is added an int or a function? I can imagine an implementation where "added" is evaluated lazily only on use (like Schroedinger's Cat on opening the box). Is there any guarantee of when the addition is performed?

Upvotes: 17

Views: 2494

Answers (4)

Luaan
Luaan

Reputation: 63772

No. But kind of yes. But really, no.

You can construct a pure functional language that only has functions and nothing else. Lambda calculus is a complete algebra, so the theory is there. In this model, added can be considered a parameter-less function (in contrast to e.g. random(), where there's one parameter of type unit).

But F# is different. Since it's a rather pragmatic mix of imperative and functional programming, the result is not a function[1]. Instead, it's a value, just like a local in C#. This is no implementation detail - it's actually part of the F# specification. This does have disadvantages - it means its possible to have an ambiguous definition, where a definition could be either a value or a function definition (14.6.1).

[1] - Though in a pure functional program, you can't tell the difference - it's the same as just doing a substitution of the function with a cached value, which is perfectly legal.

Upvotes: 2

Mark Seemann
Mark Seemann

Reputation: 233505

F# is an eagerly evaluated language, so an expression like addTwo 2 2 will immediately be evaluated to a value of the int type.

Haskell, by contrast, is lazily evaluated. An expression like addTwo 2 2 will not be evaluated until the value is needed. The type of the expression would still be a single integer, though. Even so, such an expression is, despite its laziness, not regarded as a function; in Haskell, such an unevaluated expression is called a thunk. That basically just means 'an arbitrarily complex expression that's not yet evaluated'.

Upvotes: 13

Reed Copsey
Reed Copsey

Reputation: 564931

incr is a function taking one argument. Is added an int or a function?

added, in this case, is a named binding that evaluates to an int. It is not a function.

I can imagine an implementation where "added" is evaluated lazily only on use (like Schroedinger's Cat on opening the box). Is there any guarantee of when the addition is performed?

The addition will be performed immediately when the binding is generated. There is no laziness involved.

As explained by TeaDrivenDev, you can change added to be a bound function instead of a bound value by adding a parameter, which can be unit:

let added () = addTwo 2 2

In this case, it will be a function, so the addition wouldn't happen until you call it:

let result = added () // Call the function, bind output to result

Upvotes: 12

TeaDrivenDev
TeaDrivenDev

Reputation: 6629

added is not a function; it is just a value that is calculated and bound to the name on the spot. A function always needs at least one parameter; if there is nothing useful to pass, that would be the unit value ():

let added () = addTwo 2 2

Upvotes: 18

Related Questions