Scope of input haskell - haskell

I'm having trouble taking in an input. Running it through functions. And outputting it. I have tried to do this in 2 different ways but neither work. Looking around online I see everyone only using the variable of the input inside the main. This would explain why I'm getting a "not in scope" error. But how would this be possible? Here are my two attempts.
result = lcm 3 inp
main = do
inp <- getLine
putStr result
and this:
main = do
inp <- getLine
putStr result
where
result = lcm 3 inp

inp exists only within the scope of the do expression, which explains why you get an error in the first version.
As for the second version. it can be rewritten to:
main = e
where
e = do
inp <- getLine
putStr result
result = lcm 3 inp
The two where bindings have different scopes, which is why a local binding from one expression is inaccessible from the other.
This, on the other hand, should work:
main = do
inp <- getLine
let result = lcm 3 inp
putStr result
result is now defined within the do notation scope, so it can use inp. If you still want to use the where clause, result will need to accept inp as an argument:
main = do
inp <- getLine
putStr result
where
result inp = lcm 3 inp

Let's see the types of the things you use:
*Main> :t lcm
lcm :: Integral a => a -> a -> a
*Main> let result inp = lcm 3 inp
*Main> :t result
result :: Integral a => a -> a
But you read in a String:
*Main> :t getLine
getLine :: IO String
So, you need to convert a String to something like an integer, and convert an Inegral the result returned back to Striing for printing.
main = do
inp <- getLine
putStr $ show $ result (read inp)

Related

How does Haskell "desugar" getline in this do block?

I've read a few books on Haskell but haven't coded in it all that much, and I'm a little confused as to what Haskell is doing in a certain case. Let's say I'm using getLine so the user can push a key to continue, but I don't really want to interpret that person's input in any meaningful way. I believe this is a valid way of doing this:
main = do
_ <- getLine
putStrLn "foo"
I understand the basic gist of what's this is doing. getLine returns an IO String, and putStrLn takes a String and returns IO (), so if I theoretically wanted to print what the user typed into the console, I'd basically utilize the >>= operator from the Monad class. In my case, I believe my code is equivalent to getLine >> putStrLn "foo" since I'm discarding the return value of getLine.
However, what if I do this instead?
main = do
let _ = getLine
putStrLn "foo"
In this case, we're setting up a sort of lambda to work with something that will take an IO String, right? I could write a printIOString function to print the user's input and that would work fine. When I'm not actually using that IO String, though, the program behaves strangely... getLine doesn't even prompt me for input; the program just prints out "foo".
I'm not really sure what the "desugared" syntax would be here, or if that would shed some light on what Haskell is doing under the hood.
Let's warm up with a few more complicated examples.
main = do
x
x
x
putStrLn "foo"
where
x = do
getLine
What do you expect this to do? I don't know about you, but what I expect is for the program to get three lines and then print something. If we desugar the second do block, we get
main = do
x
x
x
putStrLn "foo"
where x = getLine
Since this is the desugaring of the other one, it behaves the same, getting three lines before printing. There's another line of thought that arrives at the same answer, if you don't find this first one intuitive. "Referential transparency", one of the defining features of Haskell, means exactly that you can replace a "reference" to something (that is, a variable name) with its definition, so the previous program should be exactly the same program as
main = do
getLine
getLine
getLine
putStrLn "foo"
if we are taking the equation x = getLine seriously. Okay, so we have a program that reads three lines and prints. What about this one?
main = do
x
x
putStrLn "foo"
where x = getLine
Get two lines and print. And this one?
main = do
x
putStrLn "foo"
where x = getLine
Get one line and then print. Hopefully you see where this is going...
main = do
putStrLn "foo"
where x = getLine
Get zero lines and then print, i.e. just print immediately! I used where instead of let to make the opening example a bit more obvious, but you can pretty much always replace a where block with its let cousin without changing its meaning:
main = let x = getLine in do
putStrLn "foo"
Since we don't refer to x, we don't even need to name it:
main = let _ = getLine in do
putStrLn "foo"
and this is the desugaring of the code you wrote.
The first case is desugared like you expected:
main = getLine >>= \_ -> putStrLn "foo"
which is equivalent to
main = getLine >> putStrLn "foo"
In the second case,
main = do
let _ = getLine
putStrLn "foo"
is desugared as
main = let _ = getLine in putStrLn "foo"
Since the _ = getLine value is not needed to evaluate the RHS of the let expression, the compiler is free to ignore it and the IO effect is never executed, which is why you're not prompted for CLI input anymore.
Even though both cases ignored the result of getLine the difference is that the first case evaluates getLine in an IO context while the second case evaluates getLine as a pure value. In IO the side-effects must executed and sequenced together, but in a pure context the compiler is free to ignore unused values.
I wouldn't recommend doing this as it's not very idiomatic, but you could write something like
printIOString :: IO String -> IO ()
printIOString ios = ios >>= putStrLn
and use it like printIOString getLine
According to https://stackoverflow.com/tags/do-notation/info,
do { let { _ = getLine } ; putStrLn "foo" }
=
do { let { _ = getLine } in putStrLn "foo" }
=
let { _ = getLine } in putStrLn "foo"
which by Haskell semantics is equivalent to
getLine & (\ _ -> putStrLn "foo")
=
putStrLn "foo"
(with x & f = f x), whereas indeed
do { _ <- getLine ; putStrLn "foo" }
=
getLine >>= (\ _ -> putStrLn "foo")
which can't be further simplified.

How to read/ add/ print a number string in Haskell

Below if my code right now. I want to be able to take in user input like the following: "6 1 2 3 4 5 6" and the get the sum and print. it would also be cool to understand how to use the first number entered as the total numbers. SO here the first number is 6 and the total numbers inputted is 6.
Thank you in advance for helping me with this. I have been researching for weeks and cannot figure this out.
main = do
putStrLn "Enter how many numbers:" -- clearer
num<-getLine
putStrLn("Enter a number: ")
numberString <- getLine
let numberInt =(read numberString :: Int)
print (numberInt*4)
main
It seems you either need an auxiliary recursive function for reading num integers, or some helper like replicateM, which makes writing the code a little easier.
replicateM num action runs action exactly num times, and collects all the action results in a list.
main = do
putStrLn "Enter how many numbers:" -- clearer
num<-getLine
numbers <- replicateM num $ do
putStrLn("Enter a number: ")
numberString <- getLine
return (read numberString :: Int)
-- here we have numbers :: [Int]
...
You can then continue from there.
If instead you want to use an auxiliary function, you can write
readInts :: Int -> IO [Int]
readInts 0 = return []
readInts n = do
putStrLn("Enter a number: ")
numberString <- getLine
otherNumbers <- readInts (n-1) -- read the rest
return (read numberString : otherNumbers)
Finally, instead of using getLine and then read, we could directly use readLn which combines both.
Construct a list of integers using
let l = map (\x -> read x::Int) (words "6 1 2 3 4 5 6")
in (numNumbers, numbers)
You tried to read the whole string into a single number.

Let block gives indentation error

I know what an indentation error is, but I have no idea why I'm getting this error here, while every is aligned, trying to solve it for 2 hours.
Account.hs:40:25: error:
parse error (possibly incorrect indentation or mismatched brackets)
|
40 | let amount = readLn :: IO Int
| ^
Failed, 0 modules loaded.
main = do
putStrLn $ "Press one to create a new account"
let g = getLine
enteredValue = read g :: Int
if g == 1
then do putStrLn $ "Enter your name "
let name = getLine
putStrLn $ "Enter the initial amount"
let amount = readLn :: IO Int
value = Account (name,1,amount) Saving
show value
else do putStrLn $ "Nothing"
I also tried this version but this also gives incorrect indentation or mismatched brackets:
main = do
putStrLn $ "Press one to create a new account"
let g = getLine
enteredValue = read g :: Int
if g == 1
then do putStrLn $ "Enter your name "
let name = getLine
putStrLn $ "Enter the initial amount"
amount = readLn :: IO Int
value = Account (name,1,amount) Saving
show value
else do putStrLn $ "Nothing"
The problem is here:
-- |<---- "column 0" of this 'do' block
then do putStrLn $ "Enter your name "
-- | still good; a 'let' statement:
let name = getLine
-- |<---- "column 0" of this 'let' block
putStrLn $ "Enter the initial amount"
-- | Huh, there's no '=' in ^this^ declaration?
let amount = readLn :: IO Int
-- ^^^ Why is there a 'let' within another let binding?
-- I still haven't seen a '='. Better throw a parse error.
Basically, putStrLn $ "Enter the initial amount" is aligned with name = ... in the preceding line, so the compiler reads it as a declaration (part of the same let block).
To fix your indentation errors, it should be:
main = do
putStrLn $ "Press one to create a new account"
let g = getLine
enteredValue = read g :: Int
if g == 1
then do putStrLn $ "Enter your name "
let name = getLine
putStrLn $ "Enter the initial amount"
let amount = readLn :: IO Int
value = Account (name,1,amount) Saving
show value
else do putStrLn $ "Nothing"
But then you'll run into type errors:
read g is wrong: read takes a String, but g :: IO String
g == 1 is wrong: 1 is an Int, but g :: IO String
show value is wrong: show returns a String, but you're using it as an IO action
You haven't shown the declaration of Account, but you're likely going to have issues with name and amount, too
You probably want something like:
main = do
putStrLn $ "Press one to create a new account"
g <- getLine
let enteredValue = read g :: Int
if enteredValue == 1
then do putStrLn $ "Enter your name "
name <- getLine
putStrLn $ "Enter the initial amount"
amount <- readLn :: IO Int
let value = Account (name,1,amount) Saving
putStrLn (show value)
else do putStrLn $ "Nothing"
Basically, use v <- expr to go from expr :: IO Something to v :: Something.
Other notes:
g <- getLine; let enteredValue = read g :: Int better written as enteredValue <- readLn :: IO Int
putStrLn (show value) can be shortened to print value
you don't need do for a single expression (nor $ for a single operand): ... else putStrLn "Nothing"
There is more wrong to your code than just the Indentation Errors - so my first suggestion would be reading a bit of learn you a haskell for great good.
Next there are two assignment operators in haskell - one binds the result of an action … <- … and the other one is a local definition/declaration of a pure computation let … = ….
Moreover you can improve your reading a value by taking account of the possible false input, that someone could give you (intentionally and unintentionally) by replacing read with readMaybe, where the latter returns a Maybe something, for example readMaybe "1" = Just 1 :: Maybe Int or readMaybe "foo" = Nothing :: Maybe Int.
Regarding your indentation it is best that you compare one solution to your program with yours own:
import Text.Read (readMaybe)
data Type = Saving | Checking
deriving (Show)
data Account = Account (String,Int,Int) Type
deriving (Show)
main :: IO ()
main = do
putStrLn "Press one to create a new account"
g <- getLine
let enteredValue = readMaybe g :: Maybe Int
here the result of getLine and entered value have the same scope so they have the same indentation - we only change the scope after the next if where the then-block - and the else-block do not share the 'declarations' of each branch, so you couldn't use name in the else-block, but enteredValue can be used in both.
if enteredValue == Just 1
then do putStrLn "Enter your name "
name <- getLine
putStrLn "Enter the initial amount"
amount' <- fmap readMaybe getLine
here again name and amount' share the same scope, and pattern matching on amount' creates a new scope where amount is visible and the match on Nothing where you cannot use this variable.
case amount' of
Just amount -> print $ Account (name,1,amount) Saving
Nothing -> putStrLn "Nothing"
else putStrLn "Nothing"
let is for binding values, which is done in the form let x = y+z, where x is the name (aka "identifier") being bound, and y+z is the expression to which it is being bound.
In your example, I see three bindings: name, amount, and value. The rest are not value bindings, but actions.
In the do notation, actions do not need a let. You just write them one after another. So:
let name = getLine
putStrLn $ "Enter the initial amount"
let amount = readLn :: IO Int
let value = Account (name,1,amount) Saving
show value
But wait! This is not all!
getLine is not actually an expression of type String, as you seem to be hoping here. Rather, getLine is an action. In order to get it to "run" and "produce" a String value, you need to use the <- construct instead of let:
name <- getLine
Similarly with readLn:
amount <- readLn :: IO Int
Finally, show value is not actually an action that would print the value to the screen. show is a function that takes a value and return a String. It doesn't "do" anything (i.e. doesn't produce any outside effects), so you can't use it in place of an action in the do notation. If you wanted an action that would print a value to the screen, that would be print:
print value
Gathering everything together:
name <- getLine
putStrLn $ "Enter the initial amount"
amount <- readLn :: IO Int
let value = Account (name,1,amount) Saving
print value
And after fixing all of that, you'll have similar difficulties with the first part of your program, where you have let g = getLine instead of g <- getLine.

Haskell: Print case number

I have written a Haskell code as:
loop = do
x <- getLine
if x == "0"
then return ()
else do arr <- replicateM (read x :: Int) getLine
let blocks = map (read :: String -> Int) $ words $ unwords arr
putStr "Case X : output = "; -- <- What should X be?
print $ solve $ blockPair blocks;
loop
main = loop
This terminates at 0 input. I also want to print the case number eg. Case 1, 2 ...
Sample run:
1
10 20 30
Case 1: Output = ...
1
6 8 10
Case 2: Output = ...
0
Does anyone know how this can be done? Also, If possible can you suggest me a way to print the output line at the very end?
Thanks in advance.
For the first part of your question, the current case number is an example of some "state" that you want to maintain during the course of your program's execution. In other languages, you'd use a mutable variable, no doubt.
In Haskell, there are several ways to deal with state. One of the simplest (though it is sometimes a little ugly) is to pass the state explicitly as a function parameter, and this will work pretty well given the way you've already structured your code:
main = loop 1
loop n = do
...
putStr ("Case " ++ show n ++ ": Output = ...")
...
loop (n+1) -- update "state" for next loop
The second part of your question is a little more involved. It looks like you wanted a hint instead of a solution. To get you started, let me show you an example of a function that reads lines until the user enters end and then returns the list of all the lines up to but not including end (together with a main function that does something interesting with the lines using mostly pure code):
readToEnd :: IO [String]
readToEnd = do
line <- getLine
if line == "end"
then return []
else do
rest <- readToEnd
return (line:rest)
main = do
lines <- readToEnd
-- now "pure" code makes complex manipulations easy:
putStr $ unlines $
zipWith (\n line -> "Case " ++ show n ++ ": " ++ line)
[1..] lines
Edit: I guess you wanted a more direct answer instead of a hint, so the way you would adapt the above approach to reading a list of blocks would be to write something like:
readBlocks :: IO [[Int]]
readBlocks = do
n <- read <$> getLine
if n == 0 then return [] else do
arr <- replicateM n getLine
let block = map read $ words $ unwords arr
blocks <- readBlocks
return (block:blocks)
and then main would look like this:
main = do
blocks <- readBlocks
putStr $ unlines $
zipWith (\n line -> "Case " ++ show n ++ ": " ++ line)
[1..] (map (show . solve . blockPair) blocks)
This is similar in spirit to K. A. Buhr's answer (the crucial move is still passing state as a parameter), but factored differently to demonstrate a neat trick. Since IO actions are just normal Haskell values, you can use the loop to build the action which will print the output without executing it:
loop :: (Int, IO ()) -> IO ()
loop (nCase, prnAccum) = do
x <- getLine
if x == "0"
then prnAccum
else do inpLines <- replicateM (read x) getLine
let blocks = map read $ words $ unwords inpLines
prnAccumAndNext = do
prnAccum
putStr $ "Case " ++ show nCase ++ " : output = "
print $ solve $ blockPair blocks
loop (nCase + 1, prnAccumAndNext)
main = loop (1, return ())
Some remarks on the solution above:
prnAccum, the action which prints the results, is threaded through the recursive loop calls just like nCase (I packaged them both in a pair as a matter of style, but it would have worked just as fine if they were passed as separate arguments).
Note how the updated action, prnAccumAndNext, is not directly in the main do block; it is defined in a let block instead. That explains why it is not executed on each iteration, but only at the end of the loop, when the final prnAccum is executed.
As luqui suggests, I have removed the type annotations you used with read. The one at the replicateM call is certainly not necessary, and the other one isn't as well as long as blockPair takes a list of Int as an argument, as it seems to be the case.
Nitpicking: I removed the semicolons, as they are not necessary. Also, if arr refers to "array" it isn't a very appropriate name (as it is a list, and not an array), so I took the liberty to change it into something more descriptive. (You can find some other ideas for useful tricks and style adjustments in K. A. Buhr's answer.)

Technique for reading in multiple lines for Haskell IO

Basically I would like to find a way so that a user can enter the number of test cases and then input their test cases. The program can then run those test cases and print out the results in the order that the test cases appear.
So basically I have main which reads in the number of test cases and inputs it into a function that will read from IO that many times. It looks like this:
main = getLine >>= \tst -> w (read :: String -> Int) tst [[]]
This is the method signature of w: w :: Int -> [[Int]]-> IO ()
So my plan is to read in the number of test cases and have w run a function which takes in each test case and store the result into the [[]] variable. So each list in the list will be an output. w will just run recursively until it reaches 0 and print out each list on a separate line. I'd like to know if there is a better way of doing this since I have to pass in an empty list into w, which seems extraneous.
As #bheklilr mentioned you can't update a value like [[]]. The standard functional approach is to pass an accumulator through a a set of recursive calls. In the following example the acc parameter to the loop function is this accumulator - it consists of all of the output collected so far. At the end of the loop we return it.
myTest :: Int -> [String]
myTest n = [ "output line " ++ show k ++ " for n = " ++ show n | k <- [1..n] ]
main = do
putStr "Enter number of test cases: "
ntests <- fmap read getLine :: IO Int
let loop k acc | k > ntests = return $ reverse acc
loop k acc = do
-- we're on the kth-iteration
putStr $ "Enter parameter for test case " ++ show k ++ ": "
a <- fmap read getLine :: IO Int
let output = myTest a -- run the test
loop (k+1) (output:acc)
allOutput <- loop 1 []
print allOutput
As you get more comfortable with this kind of pattern you'll recognize it as a fold (indeed a monadic fold since we're doing IO) and you can implement it with foldM.
Update: To help explain how fmap works, here are equivalent expressions written without using fmap:
With fmap: Without fmap:
n <- fmap read getLine :: IO [Int] line <- getLine
let n = read line :: Int
vals <- fmap (map read . words) getLine line <- getLine
:: IO [Int] let vals = (map read . words) line :: [Int]
Using fmap allows us to eliminate the intermediate variable line which we never reference again anyway. We still need to provide a type signature so read knows what to do.
The idiomatic way is to use replicateM:
runAllTests :: [[Int]] -> IO ()
runAllTests = {- ... -}
main = do
numTests <- readLn
tests <- replicateM numTests readLn
runAllTests tests
-- or:
-- main = readLn >>= flip replicateM readLn >>= runAllTests

Resources