Pourquoi «imprimer <$> (imprimer« bonjour »)« imprimer «bonjour»?

14

Lors du calcul IO (IO ()), les deux (IO ())et ()est calculé, alors pourquoi

main :: IO (IO ())
main = print <$> (print "Hello, World!")

impression

"Hello, World!"

ne pas

IO "Hello, World!" -- ??
"Hello, World!"
qexy
la source
3
Applique fondamentalement fmap print (print "Hello World")son premier paramètre, la printfonction, au résultat de print "Hello World". C'est tout simplement l'équivalent d'invoquer une print ()fois l' print "Hello World"action effectuée.
Redu
@Redu C'est exact, mais notez que l'invocation de print ()n'est jamais évaluée, ni son action effectuée (qui s'imprimerait ()sur stdout). Donc, "invoquer print ()après ..." est un peu trompeur (OMI).
chi

Réponses:

21
main :: IO (IO ())
main = print <$> (print "Hello, World!")

équivaut, grâce aux lois de la monade, à

main :: IO (IO ())
main = do 
   result <- print "Hello, World!"
   return (print result)

Maintenant, printrenvoie toujours ()comme résultat, donc tout le code est équivalent à

main :: IO (IO ())
main = do 
   _ <- print "Hello, World!"
   return (print ())

Enfin, le résultat de mainest simplement rejeté. Autrement dit, la dernière ligne pourrait être return (putStrLn "this is ignored")et avoir le même effet.

Par conséquent, le code n'exécutera que le premier print "Hello, World!".

Je recommanderais que vous définissiez toujours main :: IO (). Haskell nous permet de déclarer main :: IO AnyTypeHere, mais c'est (OMI) déroutant.

Je vous recommande également d'utiliser putStrLnet de ne printpas imprimer de chaînes, car ce dernier cite et échappe la chaîne entière.

chi
la source
5
J'ajouterais que ce f <$> a ≡ a >>= \r -> return $ f rn'est pas seulement une chose spécifique à cette situation, mais vaut pour toute monade.
leftaroundabout