Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is something in the 'where' clause in Haskell only calculated once?

Tags:

haskell

where

When I have the following code:

func n = m ++ [1] ++ m ++ [0] ++ m
    where m = func2 n

How many times is the func2 function called? Only once, in the where clause? Or is it just calculated again every time I use m?

like image 896
Thomas Avatar asked Sep 14 '15 10:09

Thomas


People also ask

How does where work in Haskell?

Definition on Haskell Where Function. Haskell where is not a function rather it is a keyword that is used to divide the more complex logic or calculation into smaller parts, which makes the logic or calculation easy to understand and handle.

What does == mean in Haskell?

The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.


2 Answers

Maybe it's not evaluated at all (the joy of laziness) - but if it is, it should only be evaluated once - if you like, you can try for yourself with trace:

import Debug.Trace(trace)

func n = m ++ [1] ++ m ++ [0] ++ m
  where m = func2 n

func2 n = trace "called..." [n]

Here is an example in GHCi:

λ> func 3
called...
[3,1,3,0,3]

And here is one where you see that it might not get called (till you finally need to evaluate it):

λ> let v = func 4

λ> v
called...
[4,1,4,0,4]

See: at first it is not called - only when you finally evaluate v (to print it) you get the call.

like image 89
Random Dev Avatar answered Oct 26 '22 23:10

Random Dev


Carsten's answer (the value will be computed at most once) is correct as long as you have not disabled the monomorphism restriction. If you have, then m might have a polymorphic inferred type that involves a type class, and then m is not really a normal value, but rather a function that takes a type class dictionary and produces a value. Consider this example.

{-# LANGUAGE NoMonomorphismRestriction #-}

import Debug.Trace(trace)

func n = m ++ [1] ++ m ++ [0] ++ m
  where m = func2 n                     -- m :: Monad t => t a (where n :: a)

func2 n = trace "called..." (return n)  -- func2 :: Monad t => a -> t a

Then evaluating func 3 in ghci prints

called...
[3,1called...
,3,0called...
,3]
like image 36
Reid Barton Avatar answered Oct 27 '22 01:10

Reid Barton