Es ist eigentlich ziemlich einfach, mit (.) . (.)
zu kommen, es ist die Intuition dahinter, was es ziemlich schwierig zu verstehen ist.
(.)
bekommen Sie sehr weit beim Umschreiben Ausdruck in die "Rohr" Stil Berechnungen (denke an |
in Shell). Es wird jedoch schwierig zu verwenden, wenn Sie versuchen, eine Funktion zu erstellen, die mehrere Argumente mit einer Funktion benötigt, die nur eine benötigt. Als Beispiel nehmen wir eine Definition von concatMap
haben:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat (map f xs)
Erste von xs
loszuwerden, ist nur ein Standard-Betrieb:
concatMap f = concat . map f
Allerdings gibt es keine „schöne“ Weg, um sich von f
befreien. Dies wird durch die Tatsache verursacht, dass map
zwei Argumente benötigt und wir möchten concat
auf sein Endergebnis anwenden.
Sie können einige pointfree Tricks natürlich anzuwenden und weg mit nur (.)
:
concatMap f = (.) concat (map f)
concatMap f = (.) concat . map $ f
concatMap = (.) concat . map
concatMap = (concat .) . map
Aber ach, die Lesbarkeit des Codes ist meist verschwunden.Stattdessen führen wir einen neuen Kombinator ein, der genau das tut, was wir brauchen: Wenden Sie die zweite Funktion auf das Endergebnis des ersten an.
-- .: is fairly standard name for this combinator
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(f .: g) x y = f (g x y)
concatMap = concat .: map
Gut, das ist es für die Motivation. Kommen wir zum Point-Free-Business.
(.:) = \f g x y -> f (g x y)
= \f g x y -> f ((g x) y)
= \f g x y -> f . g x $ y
= \f g x -> f . g x
Jetzt kommt hier der interessante Teil. Dies ist eine weitere der pointfree Tricks, die normalerweise hilft, wenn Sie stecken bleiben: Wir schreiben .
in seine Präfixform und versuchen, von dort fortzusetzen.
= \f g x -> (.) f (g x)
= \f g x -> (.) f . g $ x
= \f g -> (.) f . g
= \f g -> (.) ((.) f) g
= \f -> (.) ((.) f)
= \f -> (.) . (.) $ f
= (.) . (.)
Wie für Intuition, gibt es diese very nice article, die Sie lesen sollten. Ich werde den Teil über (.)
paraphrasieren:
Denken sie noch einmal über das, was unser combinator tun sollte: es f
zum Ergebnis von Ergebnis von g
gelten soll (ich habe Endergebnis wurde mit in der Teil vor absichtlich, es ist wirklich, was Sie erhalten, wenn Sie vollständig anwenden - Modulo vereinheitlichen Typ Variablen mit einem anderen Funktionstyp - die g
Funktion, Ergebnis hier ist nur Anwendung g x
für einige x
).
Was bedeutet es für uns, f
auf das Ergebnis von g
anzuwenden? Nun, sobald wir g
auf einen Wert anwenden, nehmen wir das Ergebnis und wenden f
darauf an. Hört sich bekannt an: das macht (.)
.
result :: (b -> c) -> ((a -> b) -> (a -> c))
result = (.)
Nun stellt sich heraus, dass die Zusammensetzung (unser von Wort) dieser combinators ist nur eine Funktion Zusammensetzung, das heißt:
(.:) = result . result -- the result of result
@lordlupine einen perlendes Auge Knopf-nosed Mann mit Brille? –
@Will Ness Sie haben Recht ..: P –
@WillNess: Die Eule-mit-Brille Combinator – amindfv