História, principalmente. fmap é diferente de map por razões pedagógicas, liftM é diferente de fmap por razões históricas (ou seja, Functor não é uma superclasse de
Monad
12
Ah, e apenas para ser claro: eles não fazem "essencialmente" a mesma coisa. Ambos mape liftMcertamente devem fazer exatamente a mesma coisa que fmap.
CA McCann de
2
Embora fmape liftMfaça exatamente a mesma coisa, mapé claro que é apenas um caso especial deles, ou seja, algo diferente. fmap id getLineestá bem digitado, mas map id getLinenão.
Você pode perguntar por que precisamos de uma função de mapa separada. Por que não simplesmente acabar com a função de mapa somente de lista atual e renomear fmap para map em vez disso? Bem, essa é uma boa pergunta. O argumento usual é que alguém que acabou de aprender Haskell, ao usar o mapa incorretamente, prefere ver um erro sobre listas do que sobre Functors.
fmape liftMexistem porque as mônadas não eram automaticamente functores em Haskell:
O fato de termos fmap e liftM é uma consequência infeliz do fato de que a classe do tipo Monad não requer uma instância de Functor, embora matematicamente falando, toda mônada é um functor. No entanto, fmap e liftM são essencialmente intercambiáveis, uma vez que é um bug (em um sentido social e não técnico) para qualquer tipo ser uma instância de Monad sem também ser uma instância de Functor.
Não é assim que acontece. O que aconteceu foi que o tipo de mapa foi generalizado para cobrir o Functor em Haskell 1.3. Ou seja, em Haskell 1.3 fmap era chamado de mapa. Esta mudança foi então revertida no Haskell 1.4 e o fmap foi introduzido. A razão para essa mudança foi pedagógica; ao ensinar Haskell para iniciantes, o tipo muito geral de mapa tornava as mensagens de erro mais difíceis de entender. Na minha opinião, essa não era a maneira certa de resolver o problema.
E, da minha perspectiva como alguém que encontrou Haskell pela primeira vez mais de uma década depois que a mudança que @augustss descreve foi feita, e passou muito tempo ajudando pessoas que estão aprendendo o idioma agora, não está nada claro se isso ajudou em de qualquer forma. Certamente não o suficiente para compensar a redundância inútil (que por si só leva as pessoas a fazerem perguntas como esta); a Functorclasse é muito comum para ser ignorada e os iniciantes costumam ser confundidos com mensagens de erro!
CA McCann de
10
Não podemos simplesmente remover liftM? Deixe o código quebrar, quem se importa, normalmente leva menos de 2 dias para o código ser corrigido no github e depois carregado no hackage. Ou estou sendo selvagem e louco?
Tarrasch,
1
@Tarrasch: nem todo mundo usa o github, nem todos os pacotes têm um ótimo histórico de atualização no tempo, e eu, pelo menos, tento usar liftMenquanto estou em um bloco do que fmapporque ele se encaixa melhor quando uso liftM2, etc. também.
@ L01man Sim, isso será corrigido em breve. A Proposta Applicative Mônada (AMP) parece que vai passar para a próxima versão do Haskell. GHC 7.8.3 tem um novo sinalizador --fwarn-amppara ajudar a atualizar o código existente para a transição.
map
eliftM
certamente devem fazer exatamente a mesma coisa quefmap
.fmap
eliftM
faça exatamente a mesma coisa,map
é claro que é apenas um caso especial deles, ou seja, algo diferente.fmap id getLine
está bem digitado, masmap id getLine
não.Respostas:
map
existe para simplificar as operações em listas e por razões históricas (veja Qual é o objetivo do mapa em Haskell, quando há fmap? ).- Typeclassopedia , página 20
fmap
eliftM
existem porque as mônadas não eram automaticamente functores em Haskell:- Typeclassopedia , página 33
Editar: história de agustuss
map
efmap
:- Qual é o ponto do mapa em Haskell, quando há fmap?
fonte
Functor
classe é muito comum para ser ignorada e os iniciantes costumam ser confundidos com mensagens de erro!liftM
? Deixe o código quebrar, quem se importa, normalmente leva menos de 2 dias para o código ser corrigido no github e depois carregado no hackage. Ou estou sendo selvagem e louco?liftM
enquanto estou em um bloco do quefmap
porque ele se encaixa melhor quando usoliftM2
, etc. também.--fwarn-amp
para ajudar a atualizar o código existente para a transição.