IO dans Haskell ne fonctionne pas comme IO dans les langues auxquelles vous êtes habitué. Toutes les fonctions de Haskell doivent être pures: si une fonction f
est appelée avec l'argument x
, il ne doit y avoir aucune différence entre l'appeler une fois, deux fois ou une centaine de fois. Considérez ce que cela signifie pour IO, cependant. Naïvement, devrait avoir le type getLine :: String
, ou peut-être getLine ::() -> String
. (()
est le type d'unité, dont la seule valeur est ()
, c'est un peu comme un type vide dans un langage C-like, mais il y en a une seule valeur.) Mais cela signifierait que chaque fois que vous écriviez getLine
, devez retourner le même chaîne, ce qui n'est pas ce que vous voulez. C'est le but du type IO
: encapsuler actions. Ces actions sont distinctes des fonctions; ils représentent impure calcul (bien qu'ils soient eux-mêmes purs). Une valeur de type IO a
représente une action qui, lorsqu'elle est exécutée, renvoie une valeur de type a
. Ainsi, getLine
a le type getLine :: IO String
: chaque fois que l'action est évaluée, un String
est produit (en lisant à partir de l'utilisateur). De même, putStr
a le type putStr :: String -> IO()
; c'est une fonction qui prend une chaîne et renvoie une action qui, lorsqu'elle est exécutée, ne renvoie aucune information utile ... mais, en tant qu'effet secondaire, imprime quelque chose à l'écran. Vous essayez d'écrire une fonction de type IO() -> ([Char], Int)
. Ce serait une fonction qui a pris en entrée une action et retourné un tuple, qui est pas ce que vous voulez. Vous voulez une action IO (String, Int)
-an qui, lorsqu'elle est exécutée, produit un tuple constitué d'une chaîne (qui est un synonyme de [Char]
) et un nombre entier. Vous êtes presque là avec votre code actuel, aussi!Voici ce que vous aurez besoin à la place:
investinput :: IO (String, Int)
investinput = do
putStrLn "Enter Username : "
username <- getLine
putStrLn "Enter Invest Amount : "
tempamount <- getLine
let amount = read tempamount
return (username, amount)
Notez que je n'ai fait deux changements (et enlevé une ligne vide). D'abord, j'ai changé le type de la fonction, comme je l'ai dit plus haut. Deuxièmement, j'ai changé show
en read
. La fonction show
a le type Show a => a -> String
: c'est une fonction qui prend tout ce qui peut être affiché et produit une chaîne la représentant. Vous voulu read
, qui a le type Read a => String -> a
: donné une chaîne, il l'analyse et renvoie une valeur lisible.
L'autre élément que vous avez demandé concerne le retour d'un n-uplet (String, Int)
au lieu d'une action IO (String, Int)
. Il n'y a pas de moyen pur de le faire; en d'autres termes, il n'y a pas de fonction pure IO a -> a
. Pourquoi est-ce? Parce que IO a
représente une action impure qui dépend du monde réel. Si nous avions une telle fonction impossibleRunIO :: IO a -> a
, alors nous voudrions que ce soit le cas impossibleRunIO getLine == impossibleRunIO getLine
, puisque la fonction doit être pure. Mais cela est inutile, car nous voulons que impossibleRunIO
puisse réellement interagir avec le monde réel! Ainsi, cette fonction pure est impossible. Tout ce qui entre IO
ne peut jamais partir. C'est ce que fait return
: c'est une fonction avec, dans ce cas , le type return :: a -> IO a
, qui vous permet de placer des valeurs pures dans IO
. Pour toute x
, return x
est une action qui, lorsqu'elle est exécutée, produit toujours x
. C'est pourquoi vous devez terminer votre bloc do
avec le return
: username
est une valeur pure que vous avez extraite d'une action, et en tant que telle n'est visible que dans le bloc do
. Vous devez le soulever en IO
avant que le monde extérieur puisse le voir. La même chose est vraie de amount
/tempamount
.
Et juste pour la complétude: il y a une théorie globale derrière ceci qui la lie ensemble. Mais ce n'est pas du tout nécessaire pour commencer la programmation Haskell. Ce que je recommanderais de faire est structurer la plupart de votre code en tant que fonctions pures qui replient, broches et mutilent vos données. Ensuite, construisez une couche avant mince (aussi mince que possible) IO
qui interagit avec lesdites fonctions. Vous serez surpris du peu d'E/S dont vous avez besoin!
1: Il a en fait un type plus général, mais ce n'est pas pertinent pour le moment.
Essayez de supprimer la signature de type, en changeant 'show' en' read', et en ajoutant ':: Int' à la fin de la ligne où vous avez ajouté' read'. Puis chargez-le dans GHCi, essayez-le et demandez le type avec ': t'. Ce ne sera pas ce que tu as ici. –
Merci cela fonctionne. – peterwkc