2016-10-13 3 views
8

Die ganze Zeit, als irgendeine Haskell-Vorlesung von "flacher Karte" sprach, normalerweise in Bezug auf Monaden, dachte ich, dass sie aus einem Grund "flach" genannt wurde, dh sie flacht den Container ab . Sofmap und "flache Karte" in Haskell

[[1,2],[3,4]] 

würde verarbeitet werden, als ob es waren

[1,2,3,4] 

Aber jetzt entdecke ich, dass fmap und Karte sind im Grunde das gleiche, der einzige Unterschied ist die Anwendung einer für functors und der andere für nur Listen. Und das wurde am Ende nur gemacht, um Fehlermeldungen bei der Verwendung von map zu vermeiden.

Stimmt das? Und wenn ja, warum ist f in fmap zu "flach" geworden, warum nicht "funktor map"?

+3

Das 'f' in' fmap' bedeutet nicht "flach". Das Äquivalent von 'flatMap' in Haskell ist' (>> =) '. Die "map" -Funktion für Listen wurde zuerst definiert, so dass ein anderer Name für die allgemeinere "fmap" -Funktion benötigt wurde. – Lee

+3

Vielmehr ist 'fmap' die Verallgemeinerung von' map' zu anderen Funktoren neben dem Listenfunktor. Wer auch immer gesagt hat, dass "fmap" die Abkürzung für "flache Karte" war, lag falsch. – chepner

+4

Sind Sie sicher, dass der Vortrag, auf den Sie sich beziehen, sich auf "fmap" bezieht, wenn Sie "flache Karte" sagen? Es würde mehr Sinn ergeben, wenn es sich auf "concatMap" (aka '>> =') bezogen hätte, was in anderen Sprachen oft 'flatMap' genannt wird und sich so verhält, wie Sie es erwartet haben. – sepp2k

Antwort

19

Und wenn ja, warum haben f in fmap kommen „flach“ zu verstehen, warum nicht „Funktors Karte“?

Ihre Intuition ist richtig: die f in fmaptut Stand für „Funktors Karte“, nicht „flach Karte“ überhaupt. In neueren, ähnlichen Sprachen wie PureScript ist der Name nur map. Die Haskell map wurde jedoch zuerst für Listen definiert, so dass es schwierig war, einen neuen Namen zu finden. Die Verwendung des F von Functor war eine einfache, wenn nicht besonders kreative Entscheidung.

Es ist wahrscheinlicher, dass sich der Dozent auf die monadische Bindefunktion >>= bezieht. Aufgrund x >>= f Äquivalenz zu join (fmap f x), wird Bindung manchmal auch flatMap in anderen Sprachen genannt. Es hat das Verhalten, das Sie auf Listen erwarten, zum Beispiel:

> [1,2,3] >>= \x -> [x,x] 
[1,1,2,2,3,3] 

Es ist wichtig, im Auge zu behalten, wenn auch, dass diese „flache Karte“ nicht rekursiv auf eine beliebige Tiefe glättet. In der Tat ist das Schreiben einer solchen Funktion in Haskell ohne eine komplizierte Typenklassentrickerei nicht wirklich möglich. Probieren Sie es selbst aus: Wie sieht die Typensignatur für eine flatten-Funktion aus, sogar eine, die direkt auf Listen operiert?

flatten :: ??? -> [a] 

Die >>= Funktion ist sehr einfach im Vergleich: es wie fmap ist, aber jedes Ausgangselement muss in dem Funktors gewickelt wird, und >>= seicht „verflacht“, um die Ergebnisse in eine einzige Verpackung. Diese Operation ist die Essenz dessen, was eine Monade ist, weshalb die >>=-Funktion in der Monad Typklasse lebt, aber fmap in Functor ist.

Diese Antwort stammt aus einigen Kommentaren zur ursprünglichen Frage, daher habe ich sie als Community-Wiki markiert. Änderungen und Verbesserungen sind willkommen.

+0

Es sind aber nicht nur Zahlen, sondern auch eine Liste wenn es verschiedene Tiefen gibt, [[[1,2]], [3], [4]] >> = \ x -> x' produziert nur ':: (Num [t], Num t) => [[t]] ', nicht' [[1,2], 3,4] '. – trans

+0

@trans Beachten Sie, dass '[[[1,2]], [3], [4]]' kein gültiger Haskell-Wert ist.Es hat keinen Typ - es gibt weder 'Num t => [[t]]' noch 'Num t => [[[t]]] 'weil die Tiefe nicht konsistent ist. –

+0

Der Grund, warum Sie diesen Typ bekommen, ist die Art und Weise, wie 'Num' funktioniert, also ergibt sich eine Art von 'Num t => [[t]] ', wo' '1, 2]' eine 'Num' haben soll Beispiel. Natürlich nicht. Versuchen Sie es mit Nicht-Zahlen, um klarere Ergebnisse zu erhalten. –

0

Hier sind einige explizite gleichwertige Beispiele, wie man flatMap in Haskell macht.

Prelude> map (replicate 3) [1..4] 
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]] 
Prelude> fmap (replicate 3) [1..4] 
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]] 
Prelude> concat [[1,2],[3,4]] 
[1,2,3,4] 
Prelude> concat (map (replicate 3) [1..4]) 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> concat $ map (replicate 3) [1..4] 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> concatMap (replicate 3) [1..4] 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> replicate 3 `concatMap` [1..4] 
[1,1,1,2,2,2,3,3,3,4,4,4] 
Prelude> [1..4] >>= replicate 3 
[1,1,1,2,2,2,3,3,3,4,4,4] 

Es sollte klar sein, dass flatMap Karte zuerst und dann flach ist, können Sie die Ausgabe der Karte abzuflachen, wie die Liste Abflachen der Eingang gegen Sie zu verarbeiten sind (dies ist nicht flatMap ist, hat dies keine Name, es ist nur eine Wohnung und dann map).