2016-09-11 3 views
6

Ich versuche meinen Kopf um feste Punkte und rekursive Definitionen zu beugen.Warum scheint Haskells `Fix` Probleme mit Tupeln zu haben?

Dies funktioniert:

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

Dies gilt das gleiche, was die Definition von fix gegebenen Sinn macht:

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

Jetzt nehme ich anfangen, um mit rekursiv definiert Paare Messing:

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

Okay, ich sollte in der Lage sein, das mitzu schreibenauch, oder?

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

Aber es funktioniert nicht. Es sei denn, ich mache die folgende scheinbar unbedeutende Änderung:

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

Was ist der entscheidende Unterschied zwischen den letzten beiden Beispielen?

Antwort

14

Sie wollen

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

, um die Pattern-Matching faul zu machen. In let ist die LHS Muster implizit faul/unwiderlegbar.

Mit der Ebene \(u,v) -> ... wird das Argument des Lambdas angefordert, bevor eine Ausgabe erzeugt wird - dies macht die Funktion für fix zu streng. Was Sie brauchen, ist so etwas wie

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

so dass das Argument nicht von dem Lambda (es gibt keinen Konstruktor dort entsprechen) gezwungen wird. Der Lazy-Pattern-Ansatz entspricht dem obigen fst/snd.

+1

das sein sollte '\ (~ (u, v))' oder '\ ~ (u, v)' – redneb

+3

@redneb behoben. (Wortspiel beabsichtigt :-P) – chi

Verwandte Themen