Ostatnio próbuję użyć Haskell w moim prawdziwym systemie produkcji skrzynek. System typów Haskell naprawdę oferuje mi ogromną pomoc. Na przykład, kiedy zdałem sobie sprawę, że potrzebuję jakiejś funkcji typu
f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b
Istnieje rzeczywiście działa jak foldM
, foldlM
i foldrM
.
Jednak najbardziej zaskoczyła mnie definicja tych funkcji, takich jak:
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldr f' return xs z0
where f' x k z = f z x >>= k
więc funkcja f'
musi być typu:
f' :: a -> b -> b
zgodnie z wymaganiami foldr
, b
musi być zatem uprzejmy *-> m *
, aby cała definicja foldlM
mogła mieć sens.
Kolejny przykład obejmuje definicje liftA2
i<*>
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)
Wypróbowałem kilka własnych rozwiązań, zanim zajrzałem do kodu źródłowego. Ale różnica jest tak duża, że nie sądzę, żebym kiedykolwiek wymyślił takie rozwiązanie, bez względu na to, ile wierszy kodu napiszę w przyszłości.
Moje pytanie brzmi: jaki rodzaj wiedzy lub która konkretna gałąź matematyki jest niezbędna, aby ktoś mógł rozumować na tak wysoce abstrakcyjnym poziomie.
Wiem, że teoria kategorii może zaoferować pomoc i śledzę ten wspaniały wykład od dłuższego czasu i wciąż nad nim pracuję.
źródło
Odpowiedzi:
Ogólnie wyobrażam sobie logikę. Ale możesz się tego także nauczyć, robiąc to. :) Z czasem zauważysz pewne wzory, podnieś sztuczki.
Tak
foldr
z dodatkową argumentacją. Niektórzy postrzegają to jako składanie na funkcje, dzięki czemu można je łączyć.
iid
(które czasami są naprawdę<=<
ireturn
),Niektórzy uważają, że łatwiej to zrozumieć w prostszych, syntaktycznych terminach, jak
więc kiedy
g
nie jest ścisły w swoim drugim argumencie,s
może służyć jako stan przekazywany od lewej, mimo że składamy po prawej, jako jeden przykład.źródło
Najlepszym sposobem, aby to zrozumieć, jest zrobienie tego. Poniżej znajduje się implementacja
foldlM
użyciafoldl
zamiastfoldr
. To dobre ćwiczenie, spróbuj i przyjdź później do rozwiązania, które zasugeruję. Przykład wyjaśnia wszystkie powody, które podjąłem, aby to osiągnąć, które mogą być inne niż twoje i mogą być stronnicze, ponieważ już wiedziałem o używaniu akumulatora funkcji.Krok 1 : Spróbujmy pisać
foldlM
pod względemfoldl
Tutaj zdajesz sobie sprawę, że
f'
to jest czyste i musisz wyodrębnić wynikf
wpisywania dopasowania. Jedynym sposobem na „wyodrębnienie” wartości monadycznej>>=
jest użycie operatora, ale taki operator musi zostać zawinięty zaraz po użyciu.Podsumowując: za każdym razem, gdy skończysz z tym, chciałbym w pełni rozwinąć tę monadę , po prostu poddaj się. To nie jest właściwa droga
Krok 2 : Spróbujmy pisać
foldlM
w kategoriach,foldl
ale najpierw używaj[]
jako składanego, ponieważ łatwo jest dopasować wzór (tzn. Nie musimy tak naprawdę używaćfold
)Ok, to było łatwe. Porównajmy definicję ze zwykłą
foldl
definicją listFajne!! są prawie takie same. Trywialna sprawa dotyczy dokładnie tego samego. Rekurencyjne sprawa jest trochę inna, chcesz napisać coś więcej takich jak:
foldlM' f (f z0 x) xs
. Ale nie można go skompilować, jak w kroku 1, więc możesz pomyśleć , że nie chcę aplikowaćf
, tylko po to, aby przeprowadzić takie obliczenie i skomponować je>>=
. Chciałbym napisać coś więcej,foldlM' f (f z0 x >>=) xs
gdyby miał sens ...Krok 3 Zdaj sobie sprawę, że to, co chcesz kumulować, to kompozycja funkcji, a nie wynik. ( tutaj prawdopodobnie jestem stronniczy przez to, że już to wiedziałem, ponieważ to opublikowałeś ).
Poprzez rodzaj
initFunc
i wykorzystanie naszej wiedzy z kroku 2 (definicja rekurencyjna) możemy to wywnioskowaćinitFunc = return
. Definicjęf'
można uzupełnić wiedząc, żef'
należy użyćf
i>>=
.Jak widać, nie jest to takie trudne. Potrzebuje praktyki, ale nie jestem profesjonalnym programistą haskell i mógłbym to zrobić sam, to kwestia praktyki
źródło
Monad
przypadkach.Nie potrzebujesz żadnej konkretnej wiedzy z matematyki, aby napisać taką funkcję
foldM
. Używam Haskell w produkcji już od 4 lat, a także mam problemy ze zrozumieniem tej definicjifoldM
. Ale to głównie dlatego, że jest źle napisane. Nie traktuj tego jako osobistej winy, jeśli nie rozumiesz jakiegoś niejasnego kodu. Oto bardziej czytelna wersjafoldlM
Ta funkcja wciąż nie jest najłatwiejsza. Głównie dlatego, że ma nietypowe zastosowanie w
foldr
przypadku, gdy akumulator pośredni jest funkcją. Ale widać kilka majów, które czynią taką definicję bardziej czytelną:where
(dzięki czemu znasz kształt argumentów).Po obejrzeniu takiej funkcji możesz teraz wykonać technikę wnioskowania równania, aby krok po kroku rozwinąć definicję i zobaczyć, jak ona działa. Możliwość wymyślenia takich funkcji wiąże się z doświadczeniem. Nie mam silnych umiejętności matematycznych, a ta funkcja nie jest typową funkcją Haskella. Ale im więcej ćwiczysz, tym lepiej będzie :)
źródło