To what extent is Haskell lazy?

I need some clarification about laziness with Haskell.

If I have this function:

myFunction arg
  | arg == 1 = a
  | arg == 2 = a*b
  | arg == 3 = b+c
  | otherwise = (a+b)*c
     where
            a = ...
            b = ...
            c = ...
            d = ...

When I call myFunction 1 , Haskell will evaluate only the a = ... function, neither b nor c , nor d .

But if I write

myFunction arg
  | arg == 1 = a
  | arg == 2 = a*b
  | arg == 3 = b+c
  | otherwise = (a+b)*c
     where
            (a,b,c,d) = anotherFunction arg

What will Haskell's behaviour be?

  • Will it evaluate only a and 'propagate' the lazyness to anotherFunction ?
  • Or, will it evaluate the whole tuple (a,b,c,d) as result of anotherFunction ?

  • In both cases, it won't evaluate anything unless the value is demanded. One way of demanding the value is calling the function in ghci (which prints the value in ghci and hence demanding it). Assuming that you are executing the function, then in your second case it will evaluate the tuple to weak head normal form (WHNF) and then evaluate the first element in (a,b,c,d) because only that value is demanded. The other elements b , c and d will be in the thunk form. In fact you can verify that yourself:

    myFunction arg
      | arg == 1 = a
      | arg == 2 = a*b
      | arg == 3 = b+c
      | otherwise = (a+b)*c
      where
        (a,b,c,d) = anotherFunction arg
    
    anotherFunction x = (x, undefined, undefined, undefined)
    

    Demo in ghci:

    λ> myFunction 1
    1
    

    Well it is only interested in a , so that means that there is an implicit function :

    thea :: (a,b,c,d) -> a
    thea (a,_,_,_) = a
    

    In other words Haskell is not interested in the other elements of the tuple. Sometimes however the elements of the tuple share some structure. Say another function is defined as:

    anotherFunction :: Int -> (Int,Int,Int,Int)
    anotherFunction x = (z,t,f,g)
        where f = x*x
              g = f+x
              z = g-2
              t = 3
    

    In that case - in order to evaluate the first element - the third and fourth element will also be evaluated. But since you don't do anything with them, Haskell won't be interested in their result specifically.


    As others have already pointed out, only a will be evaluated.

    Keep however in mind that to exploit laziness it is crucial that anotherFunction returns a tuple before evaluating its components. For example, consider

    anotherFunction n = if p > 1000 then (n, p) else (n, 0)
      where p = product [1..n]
    

    The above will always evaluate product [1..n] , even if the caller only demands the first pair component (which is n ). This is because the if needs to be evaluated before the pair can be returned, and that forces p . By contrast,

    anotherFunction n = (n, if p > 1000 then p else 0)
      where p = product [1..n]
    

    will immediately return the pair. If only its first component is evaluated, then p will not be computed at all.

    链接地址: http://www.djcxy.com/p/42964.html

    上一篇: 数据类型中严格字段的​​优点

    下一篇: Haskell在什么程度上懒惰?