Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple example of call-by-need

I'm trying to understand the theorem behind "call-by-need." I do understand the definition, but I'm a bit confused. I would like to see a simple example which shows how call-by-need works.

After reading some previous threads, I found out that Haskell uses this kind of evaluation. Are there any other programming languages which support this feature?

I read about the call-by-name of Scala, and I do understand that call-by-name and call-by-need are similar but different by the fact that call-by-need will keep the evaluated value. But I really would love to see a real-life example (it does not have to be in Haskell), which shows call-by-need.

like image 841
vesii Avatar asked Jan 18 '19 21:01

vesii


People also ask

Which one of the following is also known as call by need?

Call by need is a memoized variant of call by name, where, if the function argument is evaluated, that value is stored for subsequent use. If the argument is pure (i.e., free of side effects), this produces the same results as call by name, saving the cost of recomputing the argument.

Is call by name lazy evaluation?

Technically, lazy evaluation means call-by-name plus Sharing. A kind of opposite is eager evaluation. Lazy evaluation is part of operational semantics, i.e. how a Haskell program is evaluated. The counterpart in denotational semantics, i.e. what a Haskell program computes, is called Non-strict semantics.

What do you understand by call by name?

Filters. (programming) An evaluation strategy in which the arguments to a function are evaluated when the function needs to use them.

Which languages are call-by-value?

Call by value is the default method in programming languages like C++, PHP, Visual Basic NET, and C# whereas Call by reference is supported only Java language. Call by Value, variables are passed using a straightforward method whereas Call by Reference, pointers are required to store the address of variables.

When to use call-by-name vs call by value?

In general, the expression e can be quite complex and significant computation may be required before a function is returned. This rule for evaluation of function application uses the call-by-value parameter passing mechanism because the argument to a function is evaluated before the function is applied. An alternative strategy is call-by-name.

What is call by reference in programming?

When we call a function by passing the addresses of actual parameters then this way of calling the function is known as call by reference. In call by reference, the operation performed on formal parameters, affects the value of actual parameters because all the operations performed on...

What are call options and how to use them?

Call Options are also used by institutions to enhance portfolio returns by writing call options. Let’s look at an example to understand this: The share of TCS is trading at $120 on 1 st March 2019. Max Mutual Fund is holding 100000 shares of TCS and doesn’t expect the price of TCS shares to move very much over the next few months.

How to call a function in C programming?

Function call by value is the default way of calling a function in C programming. Before we discuss function call by value, lets understand the terminologies that we will use while explaining this: Actual parameters: The parameters that appear in function calls. Formal parameters: The parameters that appear in function declarations.


2 Answers

The function

say_hello numbers = putStrLn "Hello!"

ignores its numbers argument. Under call-by-value semantics, even though an argument is ignored, the parameter at the function call site may need to be evaluated, perhaps because of side effects that the rest of the program depends on.

In Haskell, we might call say_hello as

say_hello [1..]

where [1..] is the infinite list of naturals. Under call-by-value semantics, the CPU would run off trying to build an infinite list and never get to the say_hello at all!

Haskell merely outputs

$ runghc cbn.hs
Hello!

For less dramatic examples, the first ten natural numbers are

ghci> take 10 [1..]
[1,2,3,4,5,6,7,8,9,10]

The first ten odds are

ghci> take 10 $ filter odd [1..]
[1,3,5,7,9,11,13,15,17,19]

Under call-by-need semantics, each value — even a conceptually infinite one as in the examples above — is evaluated only to the extent required and no more.

like image 157
Greg Bacon Avatar answered Oct 09 '22 05:10

Greg Bacon


update: A simple example, as asked for:

ff 0 = 1
ff 1 = 1
ff n = go (ff (n-1))
  where
  go x = x + x

Under call-by-name, each invocation of go evaluates ff (n-1) twice, each for each appearance of x in its definition (because + is strict in both arguments, i.e. demands the values of the both of them).

Under call-by-need, go's argument is evaluated at most once. Specifically, here, x's value is found out only once, and reused for the second appearance of x in the expression x + x. If it weren't needed, x wouldn't be evaluated at all, just as with call-by-name.

Under call-by-value, go's argument is always evaluated exactly once, prior to entering the function's body, even if it isn't used anywhere in the function's body.


Here's my understanding of it, in the context of Haskell.

According to Wikipedia, "call by need is a memoized variant of call by name where, if the function argument is evaluated, that value is stored for subsequent uses."

Call by name:

take 10 . filter even $ [1..]

With one consumer the produced value disappears after being produced so it might as well be call-by-name.

Call by need:

import qualified Data.List.Ordered as O

h = 1 : map (2*) h <> map (3*) h <> map (5*) h
    where
    (<>) = O.union

The difference is, here the h list is reused by several consumers, at different tempos, so it is essential that the produced values are remembered. In a call-by-name language there'd be much replication of computational effort here because the computational expression for h would be substituted at each of its occurrences, causing separate calculation for each. In a call-by-need--capable language like Haskell the results of computing the elements of h are shared between each reference to h.

Another example is, most any data defined by fix is only possible under call-by-need. With call-by-value the most we can have is the Y combinator.

See: Sharing vs. non-sharing fixed-point combinator and its linked entries and comments (among them, this, and its links, like Can fold be used to create infinite lists?).

like image 1
Will Ness Avatar answered Oct 09 '22 06:10

Will Ness