2016-09-11 11 views
6

Próbuję zgiąć głowę wokół stałych punktów i definicji rekursywnych.Dlaczego "fix" haskella wydaje się mieć problemy z krotkami?

to działa:

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

To nie to samo, co ma sens, biorąc pod uwagę definicję fix:

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

Załóżmy teraz zacznę bawić z rekurencyjnie zdefiniowanych parach:

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

Okej, powinienem móc napisać to z fix też, prawda?

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

Ale to nie działa. Jeśli nie dokonam następującej pozornie banalnej zmiany:

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

Jaka jest zasadnicza różnica między dwoma ostatnimi przykładami?

Odpowiedz

14

Chcesz

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

tak aby wzorzec dopasowania leniwy. W kodzie let wzorzec LHS jest domyślnie leniwy/niezapisywalny.

Ze zwykłym \(u,v) -> ... argument lambda będzie wymagany przed wyprodukowaniem jakiegokolwiek wyjścia - to powoduje, że funkcja jest zbyt restrykcyjna dla fix. To, czego potrzebujesz, to coś takiego, jak tak, że argument nie jest wymuszany przez lambdę (nie ma tam konstruktora do dopasowania). Metoda leniwego wzorca jest równoważna powyższemu fst/snd.

+1

To powinno być '\ (~ (u, v))' lub '\ ~ (u, v)' – redneb

+3

@redneb Naprawiono. (kalambur przeznaczony :-P) – chi

Powiązane problemy