2016-01-31 14 views
6

Rozważmy następujące definicje Haskell, zaczerpnięte z this excellent Haskell video on YouTube:Jak szwedzki jest bardzo bardzo szwedzkim pozdrowieniem?

import Data.List 
greeting = "Hello" 
swedish = intersperse 'f' 
very f x = f (f (f x)) 

Jeśli załadować je do GHCi widzimy następujące wyniki:

ghci> swedish greeting 
"Hfeflflfo" 
ghci> very swedish greeting 
"Hfffffffeffffffflffffffflfffffffo" 
ghci> very very swedish greeting 
"Hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 
fffffffffffffffffffffffffffff... (536,870,913 chars total) 

Pierwsze dwa wyjścia doskonale rozumiem. A swedish greeting jest przeplatany z f s, a very swedish greeting jest po prostu swedish (swedish (swedish greeting)), który wychodzi potrójnie przeplatane.

Ale co dokładnie dzieje się w trzeciej linii wejściowej? Moje (raczej niekompletne) zrozumienie składni Haskella mówi, że sekwencja wyrażeń oddzielonych spacjami interpretowana jest jako wywołanie funkcji, gdzie pierwszym wyrażeniem jest funkcja, a reszta to argumenty. W takim przypadku, w jaki sposób zewnętrzny numer very jest wywoływany z trzema argumentami (very, swedish i greeting), gdy jest zdefiniowany tylko jako akceptacja dwóch?

Jeśli to pomaga, wydaje się, że very very swedish greeting jest odpowiednikiem swedish $ swedish $ swedish $ swedish $ ... (27 layers of swedish) ... $ swedish $ swedish greeting.

+0

nowoczesne brukiew przywitać "Hi!" – epsilonhalbe

Odpowiedz

11

Mówiłeś:

My (raczej niepełna) znajomość składni Haskell mówi, że rozdzielona spacjami sekwencja wyrażeń jest interpretowana jako wywołanie funkcji, gdzie pierwszym wyrażeniem jest funkcja, a reszta to argumenty.

Masz rację, że to nie jest kompletne zrozumienie tego, co się właściwie dzieje. Z Twojego przykład:

very very swedish greeting 

To jest taka sama, jak:

((very very) swedish) greeting 

To dlatego, że aplikacja jest funkcja wiązanie lewe. Ponadto każda funkcja w Haskell pobiera jedno wejście i zwraca jeden wynik.To, co uważasz za funkcje akceptujące wiele wejść, to w rzeczywistości funkcje, które akceptują pojedyncze wejście i zwracają funkcję jako wynik.

Wyjaśnia to również, dlaczego strzałki funkcyjne strzałek (->) i prowadzą do typów funkcji. Rozważyć rodzaj ++:

(++) :: [a] -> [a] -> [a] 

To jest taka sama, jak:

(++) :: [a] -> ([a] -> [a]) 

Możesz myśleć operatora ++ za sobą dwie listy i powrót do listy, ale w rzeczywistości jest funkcją jedno wejście (lista), które zwraca funkcję jednego wejścia (inna lista), które zwraca listę.

Łącznie można mieć nadzieję, że very very jest prawidłowym wyrażeniem samo w sobie (i ma ten sam typ co very).

very very x 

odpowiada:

very (very (very x)) 
+0

Każdy powód, dla którego 'bardzo bardzo x' nie tworzy nieskończonej pętli? –

3

aplikacja Funkcja jest wiązanie lewe, więc

very very swedish greeting 

jest równoważna

((very very) swedish) greeting 

very ma typ (t -> t) -> t -> t. very mogą być przekazywane jako pierwszy argument do very

very  :: (t  -> t  ) -> t  -> t 
    very :: (t -> t) -> (t -> t) 
very very ::       (t -> t) -> (t -> t) 

very very jest również funkcja, ma typ (t -> t) -> t -> t. Od swedish ma typ String -> String, można go przekazać do very very. Funkcja wynikające ma typ String -> String

((very very) swedish) :: String -> String 

Funkcja z rodzaju String -> String mogą być stosowane do greeting :: String

(((very very) swedish) greeting) :: String