Tak, twoja intuicja o funkcje nie wymagające wszystkie swoje argumenty jest na miejscu. A gdy jedna funkcja przyjmuje inną funkcję jako parametr, aby w wyniku tego zwrócić inną funkcję, nazywa się ją "currying". Patrz: http://en.wikipedia.org/wiki/Currying.
(Na marginesie, to faktycznie odkrył (lub odnaleziony) przez Haskell Curry, która jest jak nasz Haskell zawdzięcza swoją nazwę.)
Jeśli pomysł zmiękczania wciąż potrzebuje czasu, aby zatopić w , to może pomóc: W rzeczywistości są dwie funkcje zdefiniowane w Prelude
o nazwie curry
i uncurry
. Prowadzą one następujące typy:
Prelude> :t curry
curry :: ((a, b) -> c) -> a -> b -> c
Prelude> :t uncurry
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry
wybija 2 argumentu curry funkcja (lub funkcji, które ma funkcję jeden argument zwracającej funkcji jednego argumentu) i wytwarza uncurrried funkcji lub funkcja, która przyjmuje wszystkie argumenty za jednym razem(jako krotka.)
curry
, jak może sugerować nazwą i jej rodzaju, idzie w drugą stronę, tak że ma curry funkcyjny (funkcję, która pobiera wszystkie argumenty na raz) i wywołuje funkcję, która przyjmuje jeden argument i zwraca funkcję, która przyjmuje drugi argument.
Większość języków programowania pracuje domyślnie w sposób nieskrywany, podajesz wszystkie argumenty i uzyskujesz wynik, podczas gdy Haskell jest domyślnie ustawiony.
teraz na przykład uncurry
, możemy podjąć prostą funkcję, (+)
:
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> (+) 1 2
3
Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> :t uncurry (+)
uncurry (+) :: Num c => (c, c) -> c
Prelude> uncurry (+) (1,2)
3
I moglibyśmy to zrobić także z const
jeśli chcemy:
Prelude> :t const
const :: a -> b -> a
Prelude> const 1 2
1
Prelude> :t uncurry const
uncurry const :: (c, b) -> c
Prelude> uncurry const (1,2)
1
Ale mając Niespokojna wersja const
jest po prostu niezbyt przydatna, ponieważ nie ma sensu posiadanie funkcji, która pobiera dwa argumenty i zawsze zwraca pierwszą, jeśli trzeba określić wszystkie argumenty z góry.
const
jest przydatna właśnie dlatego, że jest curry i może być podana w miejscu, gdzie potrzebna jest funkcja, która pobiera dwa argumenty i po prostu zwraca pierwszą.
Podobnie jak w foldr1
, na przykład:
Prelude> :t foldr1
foldr1 :: (a -> a -> a) -> [a] -> a
Jeśli pierwszy argument jest curry funkcją dwóch argumentów. A ponieważ wartość zwracana funkcji może mieć funkcję, może to być również tak z const
:
Prelude> :t const id
const id :: b -> a -> a
const id
prostu przyjmuje argument dowolnego typu b
i zwraca funkcję id
.
Więc jeśli możemy zastosować const id
krok po kroku:
Prelude> :t const id 1
const id 1 :: a -> a
const id 1
lub const id anyOtherValueHere
prostu zwraca funkcję id. które mogą być używane tak lubił:
Prelude> :t const id "Giraffe" 100
const id "Giraffe" 100 :: Num a => a
Prelude> const id "Giraffe" 100
100
Prelude> :t const id (\a b -> undefined) 100
const id (\a b -> undefined) 100 :: Num a => a
Prelude> const id (\a b -> undefined) 100
100
Więc const
naprawdę ignoruje swój drugi argument. Bezpośrednio powyżej, jest jak stosowanie id
100.
So, foldr1 (const id)
prostu pobiera listę i utrzymuje stosowania id
do każdego zestawu dwóch elementów i zachowaniu drugi (bo const id
zwraca wartość id
na drugiego argumentu przekazanego in), dopóki nie mamy ostatniego elementu.
Bez wątpienia znajdziesz w swoich przyszłych przygodach Haskell, że możliwość skorzystania z curry jest raczej popularnym "sportem" Haskella i ideałem elegancji, do którego wielu stara się dotrzeć. Koncepcja jest znana jako [Point-free style] (http://www.haskell.org/haskellwiki/Pointfree). Jednym z powodów, dla których jest to miłe, jest możliwość wyświetlenia funkcji ** kompozycji innych funkcji. Na przykład zamiast 'addAndTimes x = 4 * (2 + x)', które jest funkcją na x, możesz zamiast tego powiedzieć 'addAndTimes = (* 4).(+ 2) ', co jest po prostu kompozycją funkcji' (+ 2) 'i' (* 4) '. –