digitToInt, wrong datatypes and Unknown Exceptions - haskell

I earlier posted almost the same code where I created a lot of errors with lines I didn't even need. previous post
Now I took away the type signatures and my problems were reduced to 3.
And maybe now I might be able to explain what my problems are.
What ghci shows:
C:\Users\MATZE\Desktop\star.hs:8:25:
Couldn't match expected type `IO b0' with actual type `Int'
In the return type of a call of `digitToInt'
In a stmt of a 'do' block: temp <- digitToInt n
In the expression:
do { temp <- digitToInt n;
if (((c < 0) && (temp < 6) && (temp > 0))
|| (bs !! c >= temp)) then
do { return temp }
else
do { putStrLn "Ung\252ltige Eingabe";
.... } }
C:\Users\MATZE\Desktop\star.hs:20:66:
Couldn't match expected type `Int' with actual type `[Char]'
In the second argument of `(!!)', namely `l'
In the first argument of `replicate', namely `(bs !! l)'
In the second argument of `($)', namely
`replicate (bs !! l) (" *")'
C:\Users\MATZE\Desktop\star.hs:36:17:
Couldn't match type `IO' with `[]'
Expected type: [()]
Actual type: IO ()
In the return type of a call of `putStrLn'
In a stmt of a 'do' block:
putStrLn ("#Spieler " ++ show (pl - 1) ++ "hat gewonnen!")
In the expression:
do { putStrLn ("#Spieler " ++ show (pl - 1) ++ "hat gewonnen!") }
When I try to load this:
import Data.Char
board = [5,4,3,2,1]
--getMove :: [Int] -> Int -> IO Int
getMove bs c = do
n <- getChar
if isDigit n then do
temp <- digitToInt n
if (((c<0) && (temp<6) && (temp > 0))|| (bs!!c >= temp)) then do
return temp
else do
putStrLn "Ungültige Eingabe"
getMove bs c
else do
putStrLn "Ungültige Eingabe"
getMove bs c
--drawBoard :: [Int] -> Int -> String -> IO String
drawBoard bs l = do
putStrLn (show ((l + 1)++":" ++ (concat $ replicate (bs!!l) (" *") )))
if l < 3 then do
drawBoard bs (l + 1)
else do
putStrLn "\n"
--mainloop :: [Int] -> Int -> IO()
mainloop bs pl = do
line <- (getMove bs (-1))-1
number <- getMove bs line
b1s <- take line bs ++ [ ((bs!!line) - number) ] ++ drop (line + 1) bs
drawBoard b1s 0
if ((sum b1s) /= 0) then do
mainloop b1s ((pl `mod` 2) + 1)
else do
putStrLn ("#Spieler "++ show(pl -1)++"hat gewonnen!")
--main :: IO()
main = do
mainloop board 1
Why is there a problem with the digitToInt ?
Why does ghci think "l" is a [char] ?
And what does the last Exception even mean.

The arrow in do notation binds the results of a monadic computation, so
do ...
temp <- digitToInt n
...
expects digitToInt n to have a monadic type, IO a in your case. Instead, the way to bind pure values is with let:
do ...
let temp = digitToInt n
...
The second error has to do with the type of l, which apparently is inferred to be String (a.k.a. [Char]). First of all, I recommend that you uncomment your type signature, to make sure that everything has the type that you think it does. In this case the signature for drawBoard should have one fewer argument,
drawBoard :: [Int] -> Int -> IO ()
The actual reason for the error is the mismatched parentheses show ((l + 1)++":"++..., here you concatenate (l + 1) with a string. You probably meant to write show (l + 1)++":"++....
The third error is similar to the first, you should write
let b1s = take line (bs ++ [ ((bs!!line) - number) ] ++ drop (line + 1) bs)
instead of using an arrow.
Finally you are trying to use ...-1 to subtract from a monadic computation that returns a number. You first need to bind the result of the computation, and then subtract 1. Or you can use fmap/liftM to do this.
As a stylistic suggestion: all of your code lives in the IO monad, while much of it doesn't have to. For example, you can draw a board to a String, and then print it in one go.

Related

Haskell: Getting error when accepting string input in user defined function

I'm a newbie in Haskell. Was trying a code to take input string in user defined function and further perform tasks as per argument passed to function in main.
main :: IO()
main=do
{
print(f 2)
}
f::Int->Int
f n=do
{
inp<-getLine;
if (inp=="hello") then (n+2);
else (n);
}
Since this function takes int and returns int, I defined it as Int->Int. However I feel something's missing.
I'm getting the following error:-
[1 of 1] Compiling Main ( main.hs, main.o )
main.hs:9:5: error:
• Couldn't match expected type ‘Int’ with actual type ‘IO b0’
• In a stmt of a 'do' block: inp <- getLine
In the expression:
do inp <- getLine
if (inp == "hello") then (n + 2) else (n)
In an equation for ‘f’:
f n
= do inp <- getLine
if (inp == "hello") then (n + 2) else (n)
|
9 | inp<-getLine;
| ^^^^^^^^^^^^
main.hs:10:29: error:
• Couldn't match expected type ‘IO b0’ with actual type ‘Int’
• In the expression: (n + 2)
In a stmt of a 'do' block:
if (inp == "hello") then (n + 2) else (n)
In the expression:
do inp <- getLine
if (inp == "hello") then (n + 2) else (n)
|
10 | if (inp=="hello") then (n+2);
| ^^^
main.hs:11:29: error:
• Couldn't match expected type ‘IO b0’ with actual type ‘Int’
• In the expression: (n)
In a stmt of a 'do' block:
if (inp == "hello") then (n + 2) else (n)
In the expression:
do inp <- getLine
if (inp == "hello") then (n + 2) else (n)
|
11 | else (n);
| ^
How to rectify this error??
A do block almost always indicates that you are defining a monadic computation(1). Therefore the type of f has to be Int -> IO Int (IO is induced by the use of getLine here). Additionally, since the result has to be contained in a monadic context, you should wrap n+2 and n with return.
So the final code of f should be
f :: Int -> IO Int
f n = do
inp <- getLine
if inp == "hello" then return (n + 2)
else return n
Note that the use of f in main has to be adjusted accordingly.
(1)sometimes applicative, but anyway

How to print individual elements of a list in Haskell?

I am a beginner in Haskell and I wanted to know if it was possible to print individual elements of a given list. I tried solving this problem but have failed. This is the code:
main :: IO()
main = do
let list = [1,2,3]
let size = length list
let temp = print_elem list size
print temp
print_elem :: [Int] -> Int -> Int
print_elem xs x = do
let size = length xs
let idx = size - x
let element = xs !! idx
putStr (show element)
putStr(" ")
let dummy = print_elem (xs (x-1))
return " "
I wanted to print something like this
1 2 3
If I simply use putStr (show list) it will display [1,2,3] and I don't want that.
But when I run this code multiple errors occur
printelem.hs:14:5: error:
* Couldn't match expected type `Int' with actual type `IO b0'
* In a stmt of a 'do' block: putStr (show element)
In the expression:
do let size = length xs
let idx = size - x
let element = xs !! idx
putStr (show element)
....
In an equation for `print_elem':
print_elem xs x
= do let size = ...
let idx = ...
let element = ...
....
|
14 | putStr (show element)
| ^^^^^^^^^^^^^^^^^^^^^
printelem.hs:16:29: error:
* Couldn't match expected type `Int -> [Int]'
with actual type `[Int]'
* The function `xs' is applied to one argument,
but its type `[Int]' has none
In the first argument of `print_elem', namely `(xs (x - 1))'
In the expression: print_elem (xs (x - 1))
|
16 | let dummy = print_elem (xs (x-1))
| ^^^^^^^^
How do you fix this issue?
You are thinking too imperatively. First, you need a list of strings, not a list of integers. That's map:
> map show [1,2,3]
["1","2","3"]
Next, you want to join them into a single, space-separate string. That's Data.List.intercalate:
> import Data.List
> intercalate " " (map show [1,2,3])
"1 2 3"
which you can then pass to putStrLn (print would give you the string representation of the string you already have):
import Data.List
main :: IO()
main = do
let list = [1,2,3]
putStrLn (intercalate " " (map show list))
One way to do it is
> mapM_ putStr (intersperse " " (map show [1,2,3])) >> putStrLn ""
1 2 3
it :: ()
This prints the elements one by one, converted to strings by show, interspersed with the spaces in between.
> intersperse " " (map show [1,2,3])
["1"," ","2"," ","3"]
it :: [[Char]]
mapM_ maps an IO action constructor putStr :: String -> IO () on each of the elements, and executes them all as one combined sequence of actions.
Finally this code prints the newline.

How can I break line on Haskell?

I tried break line using \n, putStrLn and print but nothing works.
When I use \n the result only concatenates the strings, and when I use putStrLn or print I receive a type error.
Output for \n:
formatLines [("a",12),("b",13),("c",14)]
"a...............12\nb...............13\nc...............14\n"
Output for putStrLn:
format.hs:6:22:
Couldn't match type `IO ()' with `[Char]'
Expected type: String
Actual type: IO ()
In the return type of a call of `putStrLn'
In the expression:
putStrLn (formatLine ((fst x), (snd x)) ++ formatLines xs)
In an equation for `formatLines':
formatLines (x : xs)
= putStrLn (formatLine ((fst x), (snd x)) ++ formatLines xs)
Failed, modules loaded: none.
the output for print is the same as that of putStrLn
Here is my code:
formatLine :: (String,Integer) -> String
formatLine (s, i) = s ++ "..............." ++ show i
formatLines::[(String,Integer)] -> String
formatLines [] = ""
formatLines (x:xs) = print (formatLine ((fst x), (snd x)) ++ formatLines xs)
I understand the reason of the error for print and putStrLn but i have no idea how fix it.
Split your code in two parts.
One part simply constructs the string. Use "\n" for newlines.
The second part takes the string and applies putStrLn (NOT print) to it. The newlines will get printed correctly.
Example:
foo :: String -> Int -> String
foo s n = s ++ "\n" ++ show (n*10) ++ "\n" ++ s
bar :: IO ()
bar = putStrLn (foo "abc" 42)
-- or putStr (...) for no trailing newline
baz :: String -> IO ()
baz s = putStrLn (foo s 21)
If you use print instead, you'll print the string representation, with quotes and escapes (like \n) inside it. Use print only for values that have to be converted to string, like numbers.
Also note that you can only do IO (like printing stuff) in functions whose return type is IO (something).
You need to print the results to output.
This is an IO action, and so you cannot have a function signature ending with -> String. Instead, as #chi points out, the return type should be IO (). Further, since you have the function to generate formatted string already, all you need is a function to help you map the printing action over your input list. This you can do using mapM_, like so:
formatLines::[(String,Integer)] -> IO ()
formatLines y = mapM_ (putStrLn . formatLine) y
Demo

Haskell issue (Couldn't match type 'IO Integer' with 'Int')

I have a problem with a Haskell script. I'm trying to learn Haskell through doing problems I find online. The input I get is:
Int -> Number of test cases
S1 -> String 1 for each test case
S2 -> String 2 for each test case
Each S1 and S2 is a space delimited string of numbers. I convert them to a list of Ints with the function strToIntList. I then want to process the two lists and return an integer value based on the results. I get the following error: Couldn't match type 'IO Integer' with 'Int' on line 24 and I stared for ages but just can't figure out why (full error at end of post).
If someone could explain why I'm going wrong, I would be very grateful.
This is my script:
import Data.List
import Data.List.Split
main = do
cases <- readLn
doLoop cases
toInt x = read x :: Int
strToIntList s = [read x :: Int | x <- (splitOn " " s)]
minOfTwo :: Int
minOfTwo = do
sa <- getLine
sb <- getLine
return $ minimum [1..50]
-- return $ minimum $ strToIntList sa
doLoop 0 = return ()
doLoop loopIndex = do
q <- getLine
let c = minOfTwo
print(c)
doLoop (loopIndex-1)
This is the full error I'm getting:
Couldn't match type `IO Integer' with `Int'
Expected type: IO String -> (String -> IO Integer) -> Int
Actual type: IO String -> (String -> IO Integer) -> IO Integer
In a stmt of a 'do' block: sa <- getLine
In the expression:
do { sa <- getLine;
sb <- getLine;
return $ minimum [1 .. 50] }
In an equation for `minOfTwo':
minOfTwo
= do { sa <- getLine;
sb <- getLine;
return $ minimum [1 .. 50] }
The getLine function is in the IO monad, and therefore any function that calls getLine must also be in the IO monad. Change your type signature for minOfTwo from Int to IO Int, and that particular problem will go away.
(You'll also need to change let c = minOfTwo into c <- minOfTwo.)
There may be other errors, but this is the one causing your error message.

What's wrong with the following program?

what's wrong with this code?
module Main where
import System.Environment
main :: IO ()
main = do
args <- getArgs
putStrLn ("Hello, " ++ args !! 0 ++ ", " ++ args !! 1)
putStrLn(add (read args !! 0) (read args !! 1))
add x y = x + y
Here are the error messages:
main.hs:8:15:
No instance for (Num String)
arising from a use of `add'
Possible fix: add an instance declaration for (Num String)
In the first argument of `putStrLn', namely
`(add (read args !! 0) (read args !! 1))'
In the expression: putStrLn (add (read args !! 0) (read args !! 1))
In the expression:
do { args <- getArgs;
putStrLn ("Hello, " ++ args !! 0 ++ ", " ++ args !! 1);
putStrLn (add (read args !! 0) (read args !! 1)) }
main.hs:8:25:
Couldn't match expected type `Char' with actual type `[Char]'
Expected type: String
Actual type: [String]
In the first argument of `read', namely `args'
In the first argument of `(!!)', namely `read args'
read args !! 0 should be read (args !! 0) and add x y = x + should be add x y = x + y. Also putStrLn takes a string only, so use print instead which also prints numbers.
However, seeing you are new to haskell. I rewrote part of your program to demonstrate a more haskellish way.
main = do
(arg0:arg1:restArgs) <- getArgs
putStrLn $ "Hello, " ++ arg0 ++ ", " ++ arg1
print $ add (read arg0) (read arg1)
add = (+)
I think it looks a bit cleaner now. Note that it's most often considered bad practice to use !!.
Just to add a little elaboration on the error messages and the solution given. Looking at the first error:
No instance for (Num String)
...
In the first argument of `putStrLn'
This might be a bit unclear. Have a look at the type signature for putStrLn:
putStrLn :: String -> IO ()
So, putStrLn is a function that takes a String and evaluates to an IO action. However you have directly tried to pass putStrLn some expression like (x + y), which is a number, and Strings are not numbers (in Haskell terms, its type signature is (Num t) => t).
The solution given above suggests using the print function instead:
print :: (Show a) => a -> IO ()
The difference between 'print' and 'putStrLn' is that print can take anything showable, which includes numbers.
Next up:
Couldn't match expected type `Char' with actual type `[Char]'
Expected type: String
Actual type: [String]
In the first argument of `read', namely `args'
This says the compiler expected a String as the first argument to read, but saw a list of Strings. Looking at the original code:
read args !! 0
In Haskell, function application has highest precedence, so the compiler basically reads your code like so:
(read args) !! 0
(note in particular that the application of read binds higher than the use of the !! operator). Hopefully it should be clear now that read has been applied to all of args.
As your intention seemed to be to read the first element of args, you need to use parentheses like so:
read (args !! 0)
Hope this makes the error messages a little more understandable!

Resources