Combining Maybe, IO and functions outside context result in error - haskell

Can't figure out how to make code below work. Tried all possible typesigs I think.
Code
type SerialNumber = (String, Int)
serialList :: Map.Map String SerialNumber
serialList = Map.fromList [("belt drive",("BD",0001))
,("chain drive",("CD",0002))
,("drive pulley",("DP",0003))
,("drive sprocket",("DS",0004))
]
findSerial :: Ord k => k -> Map.Map k a -> Maybe a
findSerial input = Map.lookup input
outOfContext (Just (a, b)) = (a, b)
getSerialFromUser :: IO ()
getSerialFromUser = do
putStr "Lookup part: "
input <- getLine
let output = findSerial input serialList
putStrLn "\nFound entry: " ++ output
Error
• Couldn't match expected type ‘[()]’
with actual type ‘Maybe SerialNumber’
• In the second argument of ‘(++)’, namely ‘output’
In a stmt of a 'do' block: putStrLn "\nFound entry: " ++ output
In the expression:
do putStr "Lookup part: "
input <- getLine
let output = findSerial input serialList
putStrLn "\nFound entry: " ++ output
|
62 | putStrLn "\nFound entry: " ++ output
Trying my first steps in Haskell without the books so please be gentle.

In Haskell function application is left associative, which means the expression:
putStrLn "\nFound entry: " ++ output
is parsed as
(putStrLn "\nFound entry: ") ++ output
But you probably expected it to be parsed as:
putStrLn ("\nFound entry: " ++ output)
That's why you need either to specify the parentheses explicitly or use $ operator:
putStrLn $ "\nFound entry: " ++ output
But notice, that output is of SerialNumber type, but (++) takes two lists as an argument. Therefore, you need to revise, which behaviour you want to specify to your program.

Related

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

Getting type error in function haskell

I have these functions, which someone one from stackoverflow told me while trying to explain a concept, but when I tried running it, I get a lot of errors.
type World = [String]
removeItem :: String -> World -> IO World
removeItem item world = do
if elem item world
then do putStrLn "Item removed."
return $ delete item world
else do putStrLn "No such item - " ++ item
return world
removeTwoItems a b world = do
world1 <- removeItem a world
world2 <- removeItem b world
return world2
look :: World -> IO World
look w = do
putStrLn $ "You see these items here: " ++ show w
return w
loop w = do
words <- fmap words getLine
case words of
("quit":_) -> return ()
("look":_) -> do w' <- look; loop w'
("remove":item:_) -> do w' <- removeItem item w; loop w'
_ -> do putStrLn "huh?"; loop w
main = do
let world0 = ["chair", "bucket"] -- the initial world
loop world0
The errors are:
prac.hs:12:13:
Couldn't match expected type ‘[Char]’ with actual type ‘IO ()’
In the first argument of ‘(++)’, namely
‘putStrLn "No such item - "’
In a stmt of a 'do' block: putStrLn "No such item - " ++ item
prac.hs:12:13:
Couldn't match type ‘[]’ with ‘IO’
Expected type: IO Char
Actual type: [Char]
In a stmt of a 'do' block: putStrLn "No such item - " ++ item
In the expression:
do { putStrLn "No such item - " ++ item;
return world }
In a stmt of a 'do' block:
if elem item world then
do { putStrLn "Item removed.";
return $ delete item world }
else
do { putStrLn "No such item - " ++ item;
return world }
prac.hs:29:28:
Couldn't match expected type ‘IO World’
with actual type ‘World -> IO World’
Probable cause: ‘look’ is applied to too few arguments
In a stmt of a 'do' block: w' <- look
In the expression:
do { w' <- look;
loop w' }
Failed, modules loaded: none.
Could somebody explain me this or fix this?
Function application has higher precedence than any operator, so
putStrLn "No such item - " ++ item
means
(putStrLn "No such item - ") ++ item
You need to write
putStrLn ("No such item - " ++ item)
or use the $ operator which is function application with lower precedence
instead, like this:
putStrLn $ "No such item - " ++ item

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.

Couldn't match expected type `IO b0' with actual type `[a0]'

I'm new to haskell guys. I'm trying to write a gcd executable file.
ghc --make gcd
When I compile this code I'm getting the following error.
Couldn't match expected type `IO b0' with actual type `[a0]'
In a stmt of a 'do' block:
putStrLn "GCD is: " ++ gcd' num1 num2 ++ "TADA...."
In the expression:
do { putStrLn "Hello,World. This is coming from Haskell";
putStrLn "This is the GCD";
putStrLn "Frist Number";
input <- getLine;
.... }
In an equation for `main':
main
= do { putStrLn "Hello,World. This is coming from Haskell";
putStrLn "This is the GCD";
putStrLn "Frist Number";
.... }
I don't understand where my problem is... Here is my code.
gcd' :: (Integral a) => a -> a -> a
gcd' x y = gcd' (abs x) (abs y)
where gcd' a 0 = a
gcd' a b = gcd' b (a `rem` b)
main = do
putStrLn "Hello,World. This is coming from Haskell"
putStrLn "This is the GCD"
putStrLn "Frist Number"
input <- getLine
let num1 = (read input)
putStrLn "Second Number"
input2 <- getLine
let num2 = read input2
putStrLn "GCD is: " ++ gcd' num1 num2 ++ "TADA...."
All I know is that read helps me convert my string into an int.
First, you need parentheses,
putStrLn ("GCD is: " ++ gcd' num1 num2 ++ "TADA....")
or infix function application ($):
putStrLn $ "GCD is: " ++ gcd' num1 num2 ++ "TADA...."
Without that, the line is parsed as
(putStrLn "GCD is: ") ++ gcd' num1 num2 ++ "TADA...."
and the concatenation of the IO-action putStrLn "GCD is: " with a String is what causes the - somewhat cryptic, before one has enough experience - type error.
From the context in that the line appears - in an IO-do-block - it must have type IO b for some b. But the type inferred from the application of (++) is [a] for some type a. These types cannot be matched, and that's what the compiler reports.
Note that after fixing that, you also need to convert the result of gcd' to a String,
putStrLn $ "GCD is: " ++ show (gcd' num1 num2) ++ "TADA...."
or you'll see another type error.
From the comment
To make my program look nicer. Is there a way that the input area is right next to the statement instead of a line down?
In general, yes. Instead of using putStrLn which appends a newline to the output string, use putStr which doesn't.
putStr "Second Number: "
input2 <- getLine
In interactive mode (ghci), that works well. stdout is not buffered there. For compiled programmes, stdout is usually line-buffered, that means it will not output anything until a newline shall be output or the buffer is full.
So for a compiled programme, you need to explicitly flush the output buffer,
import System.IO -- for hFlush
putStr "Second Number: "
hFlush stdout
input2 <- getLine
or turn off buffering altogether
import System.IO
main = do
hSetBuffering stdout NoBuffering
...
But at least the latter method used to not work on Windows (I'm not sure whether that's fixed, nor am I absolutely sure that hFlushing works on Windows).

Printing the values inside a tuple in Haskell

I have a list of tuples. For example: [("A",100,1),("B",101,2)]. I need to display it in a simple way. For example: "your name is: A", "Your id is: 100".
If anyone can find a solution for this, it would be a great help. Thanks in advance.
The easiest way to do this is to create a function that works for one of the elements in your list. So you'll need something like:
showDetails :: (String, Int, Int) -> String
showDetails (name, uid, _) = "Your name is:" ++ name ++ " Your ID is: " ++ show uid
Then you would apply this function to each element in the list, which means you want to use the mapping function:
map :: (a -> b) -> [a] -> [b]
So, if your list is called xs, you would want something like:
map showDetails xs
This obviously gives you a result of type [String], so you might be interested in the unlines function:
unlines :: [String] -> String
This simply takes a list of strings, and creates a string where each element is separated by a new line.
Putting this all together, then, gives you:
main :: IO ()
main = putStrLn . unlines . map showDetails $ [("A",100,1),("B",101,2)]
For a single tuple, just pattern match all the elements, and do something with them. Having a function that does that, you can use map to transform the entire list.
import Data.List (foldl')
show_tuple :: (Num a, Num b) => (String, a, b) -> String
show_tuple (name, id, something) =
"Your name is: " ++ name ++ "\n" ++
"Your ID is: " ++ (show id) ++ "\n" ++
"Your something: " ++ (show something) ++ "\n\n"
-- transforms the list, and then concatenates it into a single string
show_tuple_list :: (Num a, Num b) => [(String, a, b)] -> String
show_tuple_list = (foldl' (++) "") . (map show_tuple)
The output:
*Main Data.List> putStr $ show_tuple_list [("ab", 2, 3), ("cd", 4, 5)]
Your name is: ab
Your ID is: 2
Your something: 3
Your name is: cd
Your ID is: 4
Your something: 5
Quick and dirty solution
f (x,y,z) = "your id is " ++ (show y) ++ ", your name is " ++ (show x) ++ "\n"
main = putStrLn $ foldr (++) "" (map f [("A",100,1),("B",101,2)])
OR (by #maksenov)
main = putStrLn $ concatMap f [("A",100,1),("B",101,2)]
Please try:
get1st (a,_,_) = a
get2nd (_,a,_) = a
get3rd (_,_,a) = a
showTuples [] = ""
showTuples (x:xs) = "Your name is:" ++ show(get1st(x)) ++ " Your ID is: " ++ show(get2nd(x)) ++ "\n" ++ showTuples xs
main = do
let x = [("A",100,1),("B",101,2)]
putStrLn . showTuples $ x

Resources