What's wrong with the following program? - haskell

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!

Related

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

digitToInt, wrong datatypes and Unknown Exceptions

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.

getArgs expecting [char] instead of [string]

This code worked fine when it only took first.
I get this error after having added second.
Couldn't match expected type 'Char' with actual type 'String'
Expected type: [Char]
Actual type: [String]
In the first argument of `(++)', namely `first'
In the second argument of `(++)', namely `first ++ " " ++ last !! 0'
Which makes no sense to me because getArg is suppose to produce a list of string.
module Main where
import System.Environment
main :: IO ()
main = do
first <- getArgs
last <- getArgs
putStrLn ("Hello" ++ first ++ last !! 0)
getArgs returns a list of string, not a string. You could use it like this:
module Main where
import System.Environment
main :: IO ()
main = do
args <- getArgs
putStrLn ("Hello" ++ (args !! 0) ++ (args !! 1))
Of course, this is only a demonstration of how to use getArgs. In real program, you need to make sure you are given enough arguments before you actually use them.
You're trying to concatenate "Hello" which is a String to first which is a list of Strings.
I also don't understand why you're using getArgs twice. first == last.

Functional Purity using 'let' in Haskell

As I am working on learning Haskell, I understand it is a purely functional language. I am having trouble understanding why let-statements don't violate purity.
For example (in ghci):
Prelude> let e = exp 1
Prelude> e
2.718281828459045
Prelude> let e = 2
Prelude> e
2
isn't my second let statement producing a side effect? Or is the second let statement a new closure?
Your second let creates a new binding for e that shadows the existing variable. It does not modify e. You can easily check this with the following:
Prelude> let e = 1
Prelude> let f () = "e is now " ++ show e
Prelude> f ()
"e is now 1"
Prelude> let e = 2
Prelude> e
2
Prelude> f ()
"e is now 1"
Prelude>
let introduces a new local variable with a single unalterable value, and it has more local scope than any surrounding definitions, so for example:
*Main> (let length = 2 in show length) ++ ' ':show (length "Hello")
"2 5"
Here the first length has the value 2, but its scope local to the brackets. Outside the brackets, length means what it has always meant. Nothing has been edited, just a more local variable has been introduced that happens to have the same name as another one in a different scope. Let's make ghci mad by omitting the brackets and making it try to make length a number and a function:
*Main> let length = 2 in show length ++ ' ':show (length "Hello")
<interactive>:1:14:
No instance for (Num ([Char] -> a0))
arising from the literal `2'
Possible fix: add an instance declaration for (Num ([Char] -> a0))
In the expression: 2
In an equation for `length': length = 2
In the expression:
let length = 2 in show length ++ ' ' : show (length "Hello")
<interactive>:1:19:
No instance for (Show ([Char] -> a0))
arising from a use of `show'
Possible fix: add an instance declaration for (Show ([Char] -> a0))
In the first argument of `(++)', namely `show length'
In the expression: show length ++ ' ' : show (length "Hello")
In the expression:
let length = 2 in show length ++ ' ' : show (length "Hello")
And here's your example:
*Main> let e = exp 1 in show e ++ " " ++ let e = 2 in show e
"2.718281828459045 2"
I'll add brackets to emphasise the scope:
*Main> let e = exp 1 in (show e ++ " " ++ (let e = 2 in (show e)))
"2.718281828459045 2"
The first e is hidden rather than edited. Referential transparency is preserved, but it's definitely bad practice because it's hard to follow.
Now secretly the interactive prompt is a bit like one big do block in the IO monad, so let's look at that:
testdo = do
let e = exp 1
print e
let e = 2
print e
Now I have to admit that looks an awful lot like breaking referential transparency, but bear in mind that this looks like it does too:
testWrite = do
writeFile "test.txt" "Hello Mum"
xs <- readFile "test.txt"
print xs
writeFile "test.txt" "Yo all"
xs <- readFile "test.txt"
print xs
Now in what sense have we got referential transparency? xs clearly refers to two different strings. Well, what does this do notation actually mean? It's syntactic sugar for
testWrite = writeFile "test.txt" "Hello Mum"
>> readFile "test.txt"
>>= (\xs -> print xs
>> writeFile "test.txt" "Yo all"
>> readFile "test.txt"
>>= (\xs -> print xs))
Now it's clearer that what looks like assignment is just local scope again. You presumably are happy to do
increment :: [Int] -> [Int]
increment = \x -> map (\x -> x+1) x
Which is doing the same thing.
Summary
What appeared to be assignment is just introduction of a new local scope. Phew. If you use this a lot, you make it very unclear what your code means.

Resources