Qual è il punto di map in Haskell, quando c'è fmap?


97

Ovunque ho provato a usare map, fmapha funzionato anche. Perché i creatori di Haskell hanno sentito il bisogno di una mapfunzione? Non potrebbe essere solo ciò che è attualmente noto fmape fmappotrebbe essere rimosso dalla lingua?


11
Penso che tu stia chiedendo 'Qual è il punto di fmap in Haskell'?
zw324

11
So qual è il punto fmap. Consiste nel mappare una funzione su un'istanza di Functor. Mi chiedo quale sia lo scopo della specializzazione in map.
Clark Gaebel

Risposte:


95

Vorrei dare una risposta per attirare l'attenzione sul commento di Augustss :

In realtà non è così che succede. Quello che è successo è stato che il tipo di mappa è stato generalizzato per coprire Functor in Haskell 1.3. Cioè, in Haskell 1.3 fmap era chiamato map. Questa modifica è stata quindi ripristinata in Haskell 1.4 ed è stato introdotto fmap. La ragione di questo cambiamento era pedagogica; quando si insegnava Haskell ai principianti il ​​tipo molto generale di mappa rendeva i messaggi di errore più difficili da capire. Secondo me questo non era il modo giusto per risolvere il problema.

Haskell 98 è visto come un passo indietro da alcuni Haskeller (me compreso), le versioni precedenti hanno definito una libreria più astratta e coerente. Oh bene.


16
Questi passaggi a ritroso sono raccolti e documentati da qualche parte? Sarebbe interessante vedere cos'altro è stato considerato un passo indietro e se ci sono soluzioni migliori anche per loro.
Davorak

3
È map and fmapin circolazione da molto tempo - è stato riscaldato nuovamente nella mailing list Haskell-prime nell'agosto 2006 - haskell.org/pipermail/haskell-prime/2006-August/thread.html . Come contrappunto, preferisco lo status quo. A me sembra utile che ci sia un sottoinsieme di Haskell che corrisponde grosso modo a Miranda. Nel Regno Unito, Miranda è stata utilizzata come lingua di insegnamento per gli studenti di matematica non solo per gli studenti di informatica. Se quella nicchia non è già persa a causa di un linguaggio non funzionale (ad esempio Mathematica) non vedo Haskell con un mapriempimento unificato .
stephen tetley

35
E vorrei inoltre sottolineare, per chi non lo sapesse già, che augusto è Lennart Augustsson, che a tutti gli effetti ha fatto parte della comunità Haskell da prima che Haskell esistesse, cfr. A History of Haskell , quindi il commento in questione non è in alcun modo per sentito dire di seconda mano!
CA McCann

3
Ora c'è la pagina Nitpicks sul wiki Haskell in cui viene menzionato questo problema.
Alexey

È divertente che questa decisione sia stata presa per ragioni pedagogiche, perché ho confuso fmap con flatmap tutto il tempo durante l'apprendimento di Haskell. Avrebbero dovuto mettere insieme un focusgroup n00b. :)
Danny Andrews

27

Citando dalla Functordocumentazione su https://wiki.haskell.org/Typeclassopedia#Functor

Potresti chiedere perché abbiamo bisogno di una mapfunzione separata . Perché non farla finita con la lista di sola corrente mapla funzione, e rinominare fmapa map posto? Bene, questa è una buona domanda. Il solito argomento è che qualcuno che sta imparando Haskell, quando usa in mapmodo errato, preferirebbe di gran lunga vedere un errore sugli elenchi piuttosto che su Functor.


1
Questo ha molto senso per me.
hbobenicio

25

Hanno lo stesso aspetto sul sito dell'applicazione ma sono diversi, ovviamente. Quando applichi una di queste due funzioni, mapo fmap, a un elenco di valori, produrranno lo stesso risultato, ma ciò non significa che siano destinati allo stesso scopo.

Esegui una sessione GHCI (il Glasgow Haskell Compiler Interactive) per richiedere informazioni su queste due funzioni, quindi dai un'occhiata alle loro implementazioni e scoprirai molte differenze.

carta geografica

Interrogare GHCI per informazioni su map

Prelude> :info map
map :: (a -> b) -> [a] -> [b]   -- Defined in ‘GHC.Base’

e la vedrai definita come una funzione di ordine elevato applicabile a un elenco di valori di qualsiasi tipo che aproduce un elenco di valori di qualsiasi tipo b. Sebbene polimorfica (la ae bnella definizione precedente stanno per qualsiasi tipo), la mapfunzione è pensata per essere applicata a un elenco di valori che è solo un possibile tipo di dati tra molti altri in Haskell. La mapfunzione non può essere applicata a qualcosa che non è un elenco di valori.

Come puoi leggere dal codice sorgente di GHC.Base , la mapfunzione è implementata come segue

map _ []     = []
map f (x:xs) = f x : map f xs

che fa uso del pattern matching per estrarre la testa (la x) dalla coda (la xs) della lista, quindi costruisce una nuova lista usando il :costruttore del valore (contro) in modo da anteporre f x(leggilo come "f applicato a x" ) alla ricorsione di mapsopra la coda fino a quando l'elenco è vuoto. Vale la pena notare che l'implementazione della mapfunzione non si basa su nessun'altra funzione ma solo su se stessa.

fmap

Ora prova a interrogare per informazioni su fmape vedrai qualcosa di completamente diverso.

Prelude> :info fmap
class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b
  ...
  -- Defined in ‘GHC.Base’

Questa volta fmapè definita come una delle funzioni le cui implementazioni devono essere fornite da quei tipi di dati che desiderano appartenere alla Functorclasse del tipo. Ciò significa che possono esserci più di un tipo di dati, non solo il tipo di dati "elenco di valori" , in grado di fornire un'implementazione per la fmapfunzione. Ciò rende fmapapplicabile a un insieme molto più ampio di tipi di dati: i funtori davvero!

Come si può leggere dal codice sorgente di GHC.Base , una possibile implementazione della fmapfunzione è quella fornita dal Maybetipo di dato:

instance  Functor Maybe  where
  fmap _ Nothing       = Nothing
  fmap f (Just a)      = Just (f a)

e un'altra possibile implementazione è quella fornita dal tipo di dati 2-tuple

instance Functor ((,) a) where
  fmap f (x,y) = (x, f y)

e un'altra possibile implementazione è quella fornita dal tipo di dati list (ovviamente!):

instance  Functor []  where
  fmap f xs = map f xs

che si basa sulla mapfunzione.

Conclusione

La mapfunzione può essere applicata a nient'altro che a liste di valori (dove i valori sono di qualsiasi tipo) mentre la fmapfunzione può essere applicata a molti più tipi di dati: tutti quelli che appartengono alla classe funtore (es. Maybes, tuple, liste, ecc. ). Poiché il tipo di dati "elenco di valori" è anche un funtore (poiché fornisce un'implementazione per esso), fmappuò essere applicato anche producendo lo stesso risultato di map.

map  (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.