aplicação de função: Por que é de R $ usada aqui?
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?
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