Why does haskell `fix` seem to have tuple problems?

I am trying to bow my head around fixed points and recursive definitions.

It works:

>>> take 10 $ let x = (0:x) in x [0,0,0,0,0,0,0,0,0,0] 

This does the same thing that makes sense given the definition of fix :

 >>> take 10 $ fix (\x -> (0:x)) [0,0,0,0,0,0,0,0,0,0] 

Now suppose I start messing with recursively defined pairs:

 >>> take 10 $ fst $ let (u,v) = (0:v,1:u) in (u,v) [0,1,0,1,0,1,0,1,0,1] 

Ok, I can write this with fix too, right?

 >>> take 10 $ fst $ fix (\(u,v) -> (0:v,1:u)) *** Exception: <<loop>> 

But that will not work. If I do not make the following seemingly trivial change:

 >>> take 10 $ fst $ fix (\r -> let (u,v)=r in (0:v,1:u)) [0,1,0,1,0,1,0,1,0,1] 

What is the critical difference between the last two examples?

+6
source share
1 answer

Do you want to

 take 10 $ fst $ fix (\ ~(u,v) -> (0:v,1:u)) ^^^ 

to make the pattern a lazy match. In let the LHS pattern is implicitly lazy / incontrovertible.

If \(u,v) -> ... equal \(u,v) -> ... lambda argument will be required before any output is made - this makes the function too strict for fix . You need something like

 take 10 $ fst $ fix (\p -> (0:snd p,1:fst p)) 

so that the argument is not forcibly called by the lambda (there should be no constructor there). The lazy template method is equivalent above fst/snd .

+14
source

All Articles