Luke Palmer wrote:
In attempting to devise a variant of cycle which did not keep its
argument alive (for the purpose of cycle [1::Int..]), I came across
this peculiar behavior:
import Debug.Trace
cycle' :: (a -> [b]) -> [b]
cycle' xs = xs undefined ++ cycle' xs
take 20 $ cycle' (const $ 1:2:3:4:trace "x" 5:[])
[1,2,3,4,x
5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
Nuts. Oh, but wait:
take 20 $ cycle' (\_ -> 1:2:3:4:trace "x" 5:[])
[1,2,3,4,x
5,1,2,3,4,x
5,1,2,3,4,x
5,1,2,3,4,x
5]
Hey, it worked!
Can someone explain what the heck is going on here?
Luke
(\_ -> 1:2:3:4:trace "x" 5:[]) literally could mean your second program, but...
the 1:2:3:4:trace "x" 5:[] does not depend on the _ argument, and so it can be
lifted outside the (\_ -> ... ) and lazily evaluated once and shared between
calls. Optimization in ghc do this for you.
The definition "const x = (\_ -> x)" binds 'x' outside of the _ argument, so 'x'
is obviously outside (\_ -> ...) and will be lazily evaluated once and shared.
I see that making the binding and sharing explicit in
>> take 20 $ cycle' (let x = 1:2:3:4:trace "x" 5:[] in (\_ -> x))
> [1,2,3,4,x
> 5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]
behaves like const. And pushing the binding inside the (\_ -> ...)
take 20 $ cycle' (\_ -> let x = 1:2:3:4:trace "x" 5:[] in x)
[1,2,3,4,x
5,1,2,3,4,x
5,1,2,3,4,x
5,1,2,3,4,x
5]
behaves like your second example.
--
Chris
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe