Notação inconsistente em funções

Oct 09 2020

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

12 SriKadimisetty Oct 09 2020 at 21:17

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.

9 dfeuer Oct 09 2020 at 21:59

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.