Notação inconsistente em funções
Por que essa função é permitida:
-- function 1
myfunc :: String
myfunc = do
x <- (return True)
show x
e isso não é:
-- function 2
myfunc :: String
myfunc = do
x <- getLine
show x
O erro de compilação:
Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String
Eu entendo por que a função 2 não deveria funcionar, mas por que então a função 1 funciona?
e por que isso então funciona:
-- function 3
myfunc = do
x <- getLine
return (show x)
Eu entendo que ele retorna IO Stringentão, mas por que a função 1 também não é forçada a fazer isso?
Respostas
Na função 1 o dobloco in myfuncestá funcionando na lista mônada, pois Stringé realmente justo [Char]. Lá dentro, return Trueapenas cria [True]. Quando você faz x <- return Trueque "extratos" Truefora de [True]e liga-o x. A próxima linha se show xconverte Trueem uma String "True". que sendo o valor de retorno que o valor do compilador espera ver, acaba funcionando bem.
Enquanto isso, na function2 , o dobloco em myfunc também está trabalhando na lista mônada (pelo mesmo motivo, Stringsendo realmente [Char]), mas as chamadas getLinesó estão disponíveis na IOmônada. Portanto, sem surpresa, isso falha.
- EDITAR 1
OP adicionou uma função 3
-- function 3
myfunc :: String
myfunc = do
x <- getLine
return (show x)
Não, isso não deve funcionar pelo mesmo motivo que a função2 falha.
- EDITAR 2
OP atualizou a function3 para corrigir um erro de copiar e colar.
-- function 3
myfunc = do
x <- getLine
return (show x)
Isso é mencionado nos comentários, mas por uma questão de clareza, funciona porque, quando o tipo de informação não é especificado, o GHC faz a melhor inferência e depois de ver getLine, conclui que é IO Stringquem fornece getLine.
Observação - escrevi esta resposta com o tom mais casual que pude, sem estar errado com a intenção de torná-la acessível a um nível iniciante.
doblocos funcionam no contexto de um arbitrário Monad. O Monad, neste caso, é []. A Monadinstância para listas é baseada em compreensões de lista:
instance Monad [] where
return x = [x]
xs >>= f = [y | x <- xs, y <- f x]
Você pode remover a donotação da seguinte maneira:
myfunc :: String
myfunc = do
x <- (return True)
show x
-- ==>
myfunc = [y | x <- return True, y <- show x]
-- ==>
myfunc = [y | x <- [True], y <- show x]
Em uma compreensão de lista, x <- [True]é realmente o mesmo que let x = True, porque você está desenhando apenas um elemento da lista. Então
myfunc = [y | y <- show True]
Claro, "a lista de todos yos que yestão na show Truemoda" é justa show True.