I am a newbie in Haskell but I know C++ and Java. now I wonder how can I read a list of integers similar to this psuedocode?
cout << "Please enter the size of your list";
cin >> list_size;
int mylist[listsize];
for (int i = 0 ; i<list_size; i++) {
cout<< "please enter the next number:";
cin>> number;
mylist[i]=number;
}
The answers given in the linked question use lazy IO (through getContents
).
Personally, I don't like lazy IO, and I think trying to understand how it works in combination with do-notation is a recipe for confusion. So here's an answer that doesn't use lazy IO:
import Control.Monad(replicateM)
main :: IO ()
main = do
putStrLn "Please enter the size of your list"
times <- readLn
ns <- replicateM times
(do putStrLn "please enter the next number: "
readLn :: IO Int) -- type annotation to remove ambiguity
print ns
replicateM
takes a number n and an effectful action, and returns a new action that executes the original n times and returns a list with the results.
That can be understood as an effectful transformation on the list of prompt messages, one that substitutes each message by the value entered. A kind of "effectful map".
The function traverse
can be used here. Or perhaps for
, which is the flipped version of traverse
:
{-# language ScopedTypeVariables #-}
import Data.Traversable (for)
main :: IO ()
main = do
putStrLn "Please enter the size of your list"
times :: Int <- readLn
ns <- for [1..times]
(\prompt -> do putStrLn ("enter " ++ show prompt)
readLn :: IO Int) -- type annotation to remove ambiguity
print ns
The :: IO Int
annotation is required in the example because readLn
can read any type that has a Read
instance, but we aren't doing anything Int-specific with the results, so we need to inform the compiler about the type somehow.