1

In der Functor Klassendefinition wir die <$ Funktion definiert haben:

class Functor f where 
    fmap  :: (a -> b) -> f a -> f b 

    (<$)  :: a -> f b -> f a 
    (<$)  = fmap . const 

Die const Funktion hat die Definition:

const     :: a -> b -> a 
const x _    = x 

Ich weiß, dass die <$ Funktion entspricht:

\x -> fmap (const x) 

Wie entspricht fmap . const dem obigen Lambda-Ausdruck? ? Mein Verständnis von Funktionszusammensetzung ist, dass der Ausgabetyp const mit dem Eingabetyp fmap übereinstimmen sollte, aber der Eingabetyp fmap ist die Funktion (a -> b) nicht a was ist die const Funktion gibt aus.

+0

Ihre Frage inspirierte mich, die Definition von '<$' für 'Data.Map' zu überprüfen. In der nächsten Version wird es deutlich schneller. Vielen Dank! – dfeuer

Antwort

4

Die andere Antwort hat eine gute Arbeit, die Frage der Adressierung, „Wie funktioniert fmap . const auf die Lambda-Ausdruck gleichzusetzen oben?“, So möchte ich einen anderen Teil adressieren:

Mein Verständnis von Funktions Zusammensetzung Dieser Ausgabetyp von const sollte mit dem Eingabetyp fmap übereinstimmen, aber der Eingabetyp fmap ist die Funktion (a -> b) nicht a was die const-Funktion ausgibt.

In dieser Antwort, werde ich argumentieren, dass der Ausgangstyp const ist in der Tat eine Funktion, wie durch fmap benötigt.

Lassen sie die Arten von fmap und const umschreiben, in jedem einzelnen Typ Variablen Verwirrung zu vermeiden:

fmap :: Functor f => (a -> b) -> (f a -> f b) 
const :: c -> (d -> c) 

Nun man sich fragen müssen: Was ist der Ausgangstyp const? In Ihrer Frage legen Sie fest, dass der Ausgabetyp c ist (nach dem Korrigieren für die Umbenennung des Typs Variable wie oben). Aber das ist tatsächlich ein kleines Missverständnis; Der wahre Ausgabetyp ist d -> c!

Die Ausgabe von const ist eigentlich eine Funktion. Jetzt, wie Sie sagen, muss seine Ausgabe mit der Eingabe von fmap übereinstimmen. Mit unserer obigen Benennung müssen wir also die Gleichung d ~ a erfüllen (lesen Sie: Typ d und Typ a sind vom gleichen Typ) und erfüllen c ~ b. Dann werden wir haben:

const  :: b -> (a -> b) 
fmap   ::  (a -> b) -> (f a -> f b) 
fmap . const :: b    -> (f a -> f b) 
+0

Dies ist die Antwort, nach der ich gesucht habe. Daher ist mein Kommentar darüber, dass eine teilweise angewandte Funktion dem Funktor zugeordnet wurde, nicht korrekt. Es war tatsächlich eine Funktion von (d -> c), die angewendet wurde. –

5

Beachten Sie, dass:

(f . g) x = f (g x) 

(siehe die definition of (.)) so,

(fmap . const) x = fmap (const x) 

Original-Antwort

Für Konkretion, lassen Sie uns die IO Funktors verwenden.

fmap f arbeiten an einer IO-Berechnung durch Anwenden f auf das Ergebnis der Berechnung.

z. - getContents ist ein IO String und length ist eine Funktion auf Strings, so können wir Länge auf getContents FMAP:

getContents    :: IO String 
length     :: String -> Int 
fmap length getContents ::    IO Int 

Sobald er ausgeführt würde dies alle Standardeingabe, nehmen Sie die Länge der Eingabe lesen und senden Sie es (als IO-Aktion).

Jetzt ist const z eine Funktion, die ihr Argument ignoriert und immer z zurückgibt. Also, wenn ich fmap (const 'w') auf getContents wäre, würde ich habe:

getContents     :: IO String 
const 'w'      :: String -> Char 
fmap (const 'w') getContents ::    IO Char 

Wenn er ausgeführt wird, diese zunächst in allen Standardeingabe lesen würde, dann, dass die Eingabe verwerfen und zurück mit dem Zeichen ‚w‘.

+0

Ja, das weiß ich. Aber ich möchte wissen, wie die Zusammensetzung dem Lambda-Ausdruck entspricht. –

+0

Antwort aktualisiert. – ErikR

+0

In der Tat ist 'const x' eine partiell angewendete Funktion, die' fmap_ed 'an einen Funktor erhält, der in diesem Fall an ihn übergeben wird. –