Problema com o "Do" de Haskell
Pergunta
Eu escrevi uma função Haskell que calcula o fatorial de cada número em uma determinada lista e a imprime na tela.
factPrint list =
if null list
then putStrLn ""
else do putStrLn ((show.fact.head) list)
factPrint (tail list)
A função funciona, mas acho a terceira linha um pouco confusa. Por que o compilador (GHC) não relatou um erro, pois não há "fazer" antes da função "putstrln" (quase?)? Se eu omito "faça" da 4ª linha, um erro surge conforme o esperado.
Eu sou muito novo em Haskell e seus caminhos, então, por favor, me perdoe se eu dissesse algo excessivamente bobo.
Solução
do putStrLn ((show.fact.head) list)
factPrint (tail list)
na verdade é outra maneira de escrever
putStrLn ((show.fact.head) list) >> factPrint (tail list)
que, por sua vez, significa
putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)
o do
A notação é uma maneira conveniente de reunir essas mônadas, sem essa outra sintaxe feia.
Se você tiver apenas uma declaração dentro do do
, então você não está amarrando nada, e o do
é redundante.
Outras dicas
Se você é novo em Haskell, pense em do
semelhante ao aparelho necessário depois if
em uma linguagem do tipo C:
if (condition)
printf("a"); // braces not required
else {
printf("b"); // braces required
finish();
}
do
Funciona da mesma maneira em Haskell.
Talvez ajude a olhar para o tipo de fatrint e, em seguida, refatorar para usar a correspondência de padrões:
factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
putStrLn (show.fact.head) list
factPrint (tail list)
Então, se o FactPrint retornar IO ()
, e o tipo de putStrLn ""
é IO ()
, então é perfeitamente legal para factPrint []
para igual putStrLn ""
. Não do
Necessário-no fato, você pode apenas dizer factPrint [] = return ()
Se você não queria a nova linha de fundo.
do
é usado para unir múltiplas expressões monádicas. Não tem efeito quando seguido por apenas uma única expressão.
Para o IF para ser bem formado, é necessário apenas que a cláusula e a cláusula mais tenham o mesmo tipo. Já que ambas as cláusulas têm o tipo IO ()
este é o caso.
A palavra-chave DO é usada para sequenciamento, um if-then-else em haskell não precisa conter um do
Se cada ramificação for uma única declaração, por exemplo.
if a
then b
else c
Você precisa do do
No seu exemplo, pois você está sequenciando duas operações em sua filial. Se você omitir o do
então o factPrint(tail list)
A declaração é considerada não fazer parte da função e, portanto, o compilador reclama, pois encontrou uma declaração inesperada.