简体   繁体   中英

Scala's style val in Haskell

In Scala I can express a function which is evaluated each time I refer to it:

def function = 1 + 2 + 3

or a val which is evaluated only once

val val1 = 1 + 2 + 3

even if I call it many times.

In Haskell I can, of course, define a function (which, again, evaluates over and over again whenever I call it):

function = 1 + 2 + 3

Can I define an analog of Scala's val in Haskell?

UPDATE: The question is not about the lazy evaluation.

UPDATE2:

How many times the value of function will be evaluated?

function = 1 + 2 + 3
main = do
        print function
        print function
        print function

Haskell doesn't specify very many ways to control the number of times or order things are evaluated in. That said, GHC evaluates CAFs at most once (unless they are typeclass polymorphic). Note that with the monomorphism restriction on (the default), function = 1 + 2 + 3 defines function to be a monomorphic CAF, so function is evaluated at most once.

You will also find many people object to calling this a function, since it is not one unless you have done some pretty exotic things. (There is no arrow in its type.)

You can certainly write:

let x = 1 + 2 + 3 in ...

instead of

let myFunc () = 1 + 2 + 3 in ...

but in Haskell it doesn't really make sense to think about how often either of those is evaluated, except that the bodies with both be evaluated at least once if they're needed for a computation and never if they're not.

The key difference between Haskell and Scala here is that in Scala or any other strict language, the binding form val x = 1 + 2 + 3 tells Scala to evaluate the expression 1 + 2 + 3 and bind its result to a variable. In Haskell on the other hand, let x = 1 + 2 + 3 bind the computation 1 + 2 + 3 to x and the question of when or even whether to evaluate the expression isn't decided by the let expression at all.

Since Haskell binding forms don't get to decide the policy by which the expressions they're associated with get evaluated, there's no way to write an exact analogue of the Scala version.

EDIT: Disregard this answer. It only works when you compile without optimization. Taking my fibonacci implementation as an example, ghc -O0 -ddump-simpl main.hs gives a single fib definition in Core:

Main.fib :: forall a_agB. GHC.Num.Num a_agB => () -> [a_agB]

but compiling with O2 optimizations ghc -O2 -ddump-simpl main.hs implements the fibonacci list as a constant value at the top level

Main.$wfib :: forall a_agG. GHC.Num.Num a_agG => [a_agG]

This then gets called by the enclosing fibonacci implementation (which does take a () argument)

Main.fib =
  \ (@ a_agG) (w_stM :: GHC.Num.Num a_agG) (w1_stN :: ()) ->
    case w1_stN of _ { () -> Main.$wfib @ a_agG w_stM }

The result is, that while Main.fib doesn't get memoized, Main.$wfib will still be memoized and take up memory.


Original answer below:

As Daniel Wagner said in another answer, a definition such as this

val = 1+2+3

would only evaluate once, unless it was polymorphic. If you want to evaluate it every time you refer to it, you could do

val () = 1+2+3

This way you have to give the argument () to val , but then it won't save the computed value. This can be a good thing, if the computed value of val takes a lot of memory, but is easy to compute, and is consumed incrementally when you need it. For instance, you could have a list of the fibonacci numbers:

fib = 0 : 1 : zipWith (+) fib (tail fib)

If you now do fib !! 100000 fib !! 100000 , you will need to compute all the first 100000 fibonacci numbers. The value fib refers to this list, so it can't be garbage collected, but will hang around in memory. To counter this, you could do

fib () = let x = 0 : 1 : zipWith (+) x (tail x) in x

Since fib is now a (constant) function instead of a constant value, its value will not be saved, freeing up memory.

Edit: As Philip JF said in the comments, the content of the let expression might get lifted by an unfriendly compiler which would cause unwanted sharing

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM