Pergunta

Um tempo atrás, perguntei a um pergunta sobre $ , e obteve respostas úteis -. na verdade, eu pensei que eu entendi como usá-lo

Parece que eu estava errado: (

Este exemplo mostra-se em um tutorial:

instance Monad [] where
   xs >>= f = concat . map f $ xs

Não consigo para a vida de me ver porque $ foi utilizado lá; ghci não está me ajudando também, como até mesmo os testes eu não parecem mostrar equivalência com a versão que seria simplesmente omitir o $. Alguém pode esclarecer isso para mim?

Foi útil?

Solução

O $ é usado aqui porque tem precedência mais baixa do que a aplicação de função normal. Outra maneira de escrever esse código é assim:

instance Monad [] where
   xs >>= f = (concat . map f) xs

A idéia aqui é a primeira a construir uma função (concat . map f) e depois aplicá-lo ao seu argumento (xs). Como mostrado, isso também pode ser feito simplesmente colocando parêntesis em torno da primeira parte.

Note que omitindo o $ na definição original não é possível, que irá resultar em um erro de tipo. Isto é porque o operador composição de função (a .) tem uma prioridade mais baixa do que a aplicação função normal transformar eficazmente a expressão em:

instance Monad [] where
  xs >>= f = concat . (map f xs)

O que não faz sentido, porque o segundo argumento para o operador de composição de função não é uma função em tudo. Embora a seguinte definição faz sentido:

instance Monad [] where
  xs >>= f = concat (map f xs)

A propósito, esta é também a definição que eu prefiro, porque parece-me ser muito mais clara.

Outras dicas

Eu gostaria de explicar por que IMHO este não é o estilo usado lá:

instance Monad [] where
  xs >>= f = concat (map f xs)

concat . map f é um exemplo da chamada escrita de estilo pointfree; onde os meios pointfree "Sem o ponto de aplicação". Lembre-se que em matemática, na y=f(x) expressão, dizemos que f é aplicado sobre a x ponto. Na maioria dos casos, você pode realmente fazer uma etapa final, substituindo:

f x = something $ x

com

f = something

como f = concat . map f, e este é, na verdade estilo pointfree. Que é mais clara é discutível, mas o estilo pointfree dá um ponto de vista diferente que também é útil, por isso às vezes é usada mesmo quando não é exatamente necessário.

EDIT:. Eu substituí inútil com pointfree e corrigidos alguns exemplos, após o comentário de Alasdair, a quem devo agradecer

A razão $ é usado aqui é doe para a assinatura tipo de (.):

(.) :: (b -> c) -> (a -> c) -> a -> c

Aqui temos

map f :: [a] -> [[b]]

e

concat :: [[b]] -> [b]

Então vamos acabar com

concat . map f :: [a] -> [b]

eo tipo de (.) Pode ser escrito como

:: ([[b]] ??-> [b]) - (.)> ([A] -> [[b]]) -> [a] -> [b]

Se fôssemos usar concat . map f xs, veríamos que

map f xs :: [[b]]

E assim não pode ser usado com (.). (O tipo teria que ser () :: (a -.> B) -> a -> b

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top