[Haskell-cafe] Re: \_ -> not equivalent to const $

ChrisK haskell at list.mightyreason.com
Tue Jan 15 06:04:38 EST 2008


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



More information about the Haskell-Cafe mailing list