2017-12-31 98 views
7

fmap ist auch <$>, weil es Funktion Anwendung ($) in der Funktor Kategorie ist.

(+5) $ (*10) $ 10  -- 105 
(+5) <$> (*10) <$> [1,2,3] -- [15,25,35] 

Dann dachte ich, auch in diesem Fall <*> Funktion Anwendung in der applicative Funktorkategorie ist, und dies sollte funktionieren:

[(+5), (+10)] <*> [(*10), (*100)] <*> [1,2,3] -- ERROR 
-- however: 
[(+5), (+10)] <*> ([(*10), (*100)] <*> [1,2,3]) -- [15,25,35,...] 

So <$> funktioniert nur, weil fmap für Funktionen passiert sein Nachkomposition, also (+5) <$> (*10) wird (+5) . (*10), die dann auf [1,2,3] angewendet wird.

Allerdings Links Assoziativität für alle Anwendung Operatoren (<<= enthalten) scheint mir eine schlechte Design-Wahl, vor allem, nachdem sie die Ähnlichkeit zu $ erkannt, die bereits rechts assoziativ ist. Gibt es einen anderen Grund dafür?

+2

Funktion Anwendung ist von Natur aus links- assoziativ; eine bessere Frage wäre, warum ist '$' rechtsassoziativ? – chepner

+1

Außerdem ist "fmap" besser als Funktion * Heben * und nicht als Funktionsanwendung gedacht. Sobald 'fmap' die angehobene Funktion zurückgibt, wird sie wie jede andere Funktion angewendet; keine spezielle Anwendung erforderlich. – chepner

Antwort

7

Wirklich, der Grund ist wahrscheinlich nur, dass es <$> und <*> ermöglicht, eine Rangfolge Ebene zu teilen. Wir wollen auf jeden Fall <*> wie

Linksassoziativität so Zeug zu
Prelude> foldr <$> [(+),(*)] <*> [0,1] <*> [[1,2,3], [4,5,6]] 
[6,15,7,16,0,0,6,120] 

Werke, und das macht auch die richtige Art und Weise <$> zu verhalten, auch wenn es nicht eine höhere Priorität hat. Tatsächlich ist die Verkettung von mehreren <$> Operatoren mit Links-Assoziativität nicht sehr nützlich.

Allerdings wäre es auch nicht sehr nützlich mit Rechts-Assoziativität. Wie chepner kommentierte, ist es tatsächlich ein bisschen komisch, dass $ rechtsassoziativ ist. Sicher, das ermöglicht Schreibzusammensetzungen wie

Prelude> sum $ map (+3) $ take 19 $ cycle [4..7] 
160 

aber dann könnte dies ebenso wie die wohl eleganter geschrieben werden

Prelude> sum . map (+3) . take 19 . cycle $ [4..7] 
160 

(elegantere sage ich, weil hier die Berechnung Kette analysiert wird als eine einzige funktionale Pipeline, anstatt Imperativ-Stil “ dies tun, dann das, dann ... ”). Dank der Funktorgesetze kann dies genauso mit <$> und . wie mit $ und . erfolgen.

Der einzige Grund, warum Sie die Mehrfach- $ Stil bevorzugen könnte, ist, dass es Infix Ausdrücke in der Pipeline ermöglicht, vielleicht die häufigste Beispiel dafür ist Objektiv-Updates (die mit dem blätterte typischerweise geschrieben &, aber das Prinzip ist das gleiche): Dieses

Prelude Control.Lens> [4..7] & ix 1+~9 & ix 2*~8 
[4,14,48,7] 

funktioniert, weil $ und & sehr niedrige Priorität haben, ziemlich viel niedriger als jeder Infixoperator.Das ist nicht der Fall für <$> so können Sie nicht

Prelude Control.Lens> ix 1+~9 <$> [[4..8], [5..9]] 

<interactive>:23:1: error: 
    Precedence parsing error 
     cannot mix ‘+~’ [infixr 4] and ‘<$>’ [infixl 4] in the same infix expression 

In einem solchen Fall tun, Sie Notwendigkeit einige Klammern verwenden sowieso, und dann könnten Sie auch tun es mit den auch Low-Vorrang Zusammensetzung Operatoren von Control.Category:

Prelude Control.Lens Control.Category> (ix 1+~9 >>> ix 2*~8) <$> [[4..8], [5..9]] 
[[4,14,48,7,8],[5,15,56,8,9]] 

oder mit Pars um jeden Aktualisierungs:

Prelude Control.Lens> (ix 1+~9) . (ix 2*~8) <$> [[4..8], [5..9]] 
[[4,14,48,7,8],[5,15,56,8,9]] 
Verwandte Themen