2015-07-01 20 views
10

From the chapter on Functors in Learn You a Haskell for Great Good, Lipovača stwierdza:

„Kiedy robimy (+) <$> (+3) <*> (*100), robimy funkcję, która będzie używać + na wyniki (+3) i (*100) i powrócić to. aby wykazać na rzeczywistym przykładzie, kiedy zrobiliśmy (+) <$> (+3) <*> (*100) $ 5 The 5 pierwszy został zastosowany do (+3) i (*100), w wyniku 8 i 500. Następnie + jest wywoływana z 8 i 500, Res ulting w 508. "

Jednak gdy próbuję ocenić funkcję siebie, biorąc pod uwagę tę definicję aplikacyjnych na funktora ((->) R):

instance Applicative ((->) r) where 
    pure x = (\_ -> x) 
    f <*> g = \x -> f x (g x) 

czytam ocenę powyższej wypowiedzi, jak:

(\x -> (3 + x) (100 * x)) $ 5

Ale nie widzę, w jaki sposób możemy komponować dwa częściowo zastosowane funkcje binarne jako pojedynczy lambda (w rzeczywistości GHCi rzuca nieskończoną typu błędu próbuje powiązać to zmienna). Ponadto do interpretacji roboczego, jeśli spojrzymy na definicji typu dla <$> otrzymujemy:

(<$>) :: Functor f => (a -> b) -> f a -> f b

lub dokładniej możemy spojrzeć na jego zniesienie jako:

(<$>) :: Functor f => (a -> b) -> (f a -> f b)

Biorąc pod uwagę, że naszym funktorem w tym przypadku jest ((->) r), mogę wywnioskować, że to właśnie transformacja ma miejsce w poprzedniej ewaluacji (zakładając, że pierwsze zobiektywizowanie dzieje się pierwsze, zamiast odpowiedniej skojarzeniowej aplikacji 5):

(\x -> a + b) gdzie a = (+ 3) i b = (* 100). Jest to funkcja, która powinna zostać zwrócona. Czy jednak mam rację zakładając, że jest to ostateczna (szorstka) forma?

(\x -> (3 + x) + (100 * x)) $ 5

... co daje 508.

znajdę opis Lipovača jest bardziej zrozumiały w kategoriach jak działa wyrażenie, ale mój gut mówi mi, nie jest do końca prawda o szczegóły Gorey ramach celu Okap kompilatora Haskell. Łatwiej mi myśleć, że fmapa (+) zdarzyła się jako pierwsza, co skutkuje funkcją z dwoma funktorami, które są częściowo zastosowanymi funkcjami, które pobierają współdzielone dane wejściowe, a następnie zastosowaliśmy do niej wartość. Możemy to zrobić z powodu leniwej oceny. Czy to źle?

+1

„czytam ocenę powyższej wypowiedzi jak:' (\ x -> (3 + x) (100 * x)) 5 USD ". Podpowiedź: w twojej ocenie brakuje '((+) <$>)', ergo błąd typu. – duplode

+0

Tak, dlatego kontynuuję i włączam w drugiej połowie. – RJS

+0

Ups - nieważne, źle odczytałem środkową część pytania. – duplode

Odpowiedz

15

Po pierwsze, pamiętaj, że zarówno <$>, jak i <*> kojarzą się po lewej stronie. Nie dzieje się nic magicznego wewnętrznie i możemy zobaczyć transformację zasadniczo serią ekspansji eta i beta redukcji.Krok po kroku, wygląda to tak:

(((+) <$> (+3))   <*> (*100)) $ 5  -- Add parens 
((fmap (+) (+3))  <*> (*100)) $ 5  -- Prefix fmap 
(((+) . (+3))   <*> (*100)) $ 5  -- fmap = (.) 
((\a -> (+) ((+3) a)) <*> (*100)) $ 5  -- Definition of (.) 
((\a -> (+) (a+3))  <*> (*100)) $ 5  -- Infix + 
((\a b -> (+) (a+3) b)) <*> (*100)) $ 5  -- Eta expand 
(\x -> (\a b -> (+) (a+3) b) x ((*100) x)) $ 5 -- Definition of (<*>) 
(\x -> (\a b -> (+) (a+3) b) x (x*100)) $ 5 -- Infix * 
(\a b -> (+) (a + 3) b) 5 (5*100)    -- Beta reduce 
(\a b -> (a + 3) + b) 5 (5*100)    -- Infix + 
(5 + 3) + (5*100)        -- Beta reduce (twice) 
508           -- Definitions of + and * 

Trochę mylący, fakt, że $ Associates prawej ma mniej wspólnego z tym, co się tutaj dzieje, niż fakt, że jego stałość jest 0. Widzimy to czy możemy zdefiniować nowe operatora:

(#) :: (a -> b) -> a -> b 
f # a = f a 
infixl 0 # 

aw GHCi:

λ> (+) <$> (+3) <*> (*100) # 5 
508 
+0

Dziękuję za to, właśnie tego szukałem. Będę musiał popracować nad rozszerzeniem i redukcją ETA i Beta do przyszłego czytania. Nawet jeśli '$' jest prawostronne, to jest stosowane do thunk (czy można bezpiecznie wywołać wszystkie mapowania po lewej stronie thunk?), A zatem wszystko to jest oceniane, prawda? – RJS

+0

@RJS Możesz myśleć o 'f $ a'" zachowując się jak "' (f) (a) 'gdzie' f' i 'a' są fragmentami kodu, które mogą zawierać spacje (nie jest to jednak tak, że cały czas , zwłaszcza gdy '$' s są powiązane, ale często myślę o tym w ten sposób). Dodałem trochę o ustaleniu, prawdopodobnie powinienem to rozwinąć. Jest tak naprawdę argument (całkiem niezły), że nawiasem mówiąc, utworzyłem '$'. Nie jestem pewien, w jaki sposób bycie thunkiem jest powiązane. Co przez to rozumiesz? –

+0

Ah właśnie źle semantyka z mojej strony; słabe założenie, że wszystkie nieocenione argumenty są słabe, to wszystko. – RJS

Powiązane problemy