0
votes

Given the following:

debug = flip Debug.Trace.trace

foo = [1,2,3]

myRandom :: [a] -> IO Int
myRandom x =
  let lx = Prelude.length x
  in System.Random.randomRIO (0, lx) `debug` show lx

test = myRandom foo

multiple runs of test will produce a random number every time, but only the first call will print the length of the function argument. I assume it's only calculated once. Does Haskell memoize every function by default (in this case length)? How does this work in detail?

1
Well you explicitly "memoize" it here. Since you declare a variable lx = length x.Willem Van Onsem
test is not a function; it's an IO Int value. You can execute that action multiple times, but myRandom (which calls debug) itself is only called once.chepner
I know, within the function body. But for multiple runs of test I can't see how Haskell does it?Michiel Borkent
AFAICS the "memoization" is in the binding of test. Computing the IO Int action itself produces the trace output. The action is only computed once (the first time it's used), then reused.melpomene

1 Answers

3
votes

test is not a function that you call; it is an IO action that you execute. debug is called by myRandom, which is only called once to produce the IO action bound to test.

To get debug output for every execution of the action, you need to embed the call to debug in the action itself.

myRandom :: [a] -> IO Int
myRandom x = let lx = Prelude.length x `debug` "Getting length"
                 rnd = randomRIO (0, lx) `debug` "Getting generator"
             in debug <$> rnd <*> pure (show lx)

Now, when you evaluate test, you'll get 3 lines of output the first time (indicating that length and randomRIO are only evaluated once), but only one line of output each subsequent time (indicating that the IO action rnd is indeed executed anew each time).