Notation do incohérente dans les fonctions

Oct 09 2020

Pourquoi cette fonction est-elle autorisée:

-- function 1
myfunc :: String
myfunc = do
  x <- (return True)
  show x

et ce n'est pas:

-- function 2
myfunc :: String
myfunc = do
  x <- getLine
  show x

L'erreur de compilation:

Couldn't match type `[]' with `IO'
Expected type: IO Char
Actual type: String

Je comprends pourquoi la fonction 2 ne devrait pas fonctionner, mais pourquoi donc la fonction 1 fonctionne-t-elle?

et pourquoi cela fonctionne-t-il alors:

-- function 3
myfunc = do
  x <- getLine
  return (show x)

Je comprends qu'il retourne IO Stringalors, mais pourquoi la fonction 1 n'est-elle pas forcée non plus de le faire?

Réponses

12 SriKadimisetty Oct 09 2020 at 21:17

Dans function1, le dobloc dans myfuncfonctionne dans la monade de liste, car il Stringest vraiment juste [Char]. Là-dedans, return Truecrée juste [True]. Lorsque vous faites x <- return Trueque « extraits » Truesur [True]et se fixe à x. La ligne suivante se show xconvertit Trueen une chaîne "True". qui étant la valeur de retour que la valeur du compilateur s'attend à voir, finit par fonctionner correctement.

Pendant ce temps, dans function2 , le dobloc de myfunc travaille également sur la monade de liste (pour la même raison, Stringétant vraiment [Char]) mais sur getLinelaquelle les appels ne sont disponibles que dans la IOmonade. Donc, sans surprise, cela échoue.

- MODIFIER 1

OP a ajouté une fonction3

-- function 3
myfunc :: String
myfunc = do
  x <- getLine
  return (show x)

Non, cela ne devrait pas fonctionner pour la même raison que function2 échoue.

- MODIFIER 2

OP a mis à jour function3 pour corriger une erreur de copier-coller.

-- function 3
myfunc = do
  x <- getLine
  return (show x)

Ceci est mentionné dans les commentaires, mais pour plus de clarté, cela fonctionne parce que, lorsque les informations de type ne sont pas spécifiées, GHC fait la meilleure inférence et après avoir vu getLine, il se dit que c'est IO Stringce qui fournit getLine.

Remarque - J'ai écrit cette réponse avec un ton aussi décontracté que je pourrais le gérer sans me tromper avec l'intention de la rendre accessible à un niveau débutant.

9 dfeuer Oct 09 2020 at 21:59

doles blocs fonctionnent dans le contexte d'un arbitraire Monad. Le Monad, dans ce cas, est []. L' Monadinstance des listes est basée sur des compréhensions de listes:

instance Monad [] where
  return x = [x]
  xs >>= f = [y | x <- xs, y <- f x]

Vous pouvez désugarer la donotation ainsi:

myfunc :: String
myfunc = do
  x <- (return True)
  show x

-- ==>

myfunc = [y | x <- return True, y <- show x]

-- ==>

myfunc = [y | x <- [True], y <- show x]

Dans une compréhension de liste, x <- [True]c'est vraiment la même chose que let x = True, car vous ne dessinez qu'un élément de la liste. Donc

myfunc = [y | y <- show True]

Bien sûr, "la liste de tout yce qui yest dans show True" est juste show True.