Why am I getting problems with pattern matching? - haskell

I am getting a parse error in my code and I don't know why. I can't see any problems with the code as it's the same syntax as pattern matching I have used in the past.
My code:
transaction_to_string (sob : unit : price : stock : day) :: Transaction
| sob == 'S' = "Sold " ++ (show unit) ++ " units of " ++ (show stock) ++ " for " ++ (show price) ++ " pounds each on day " ++ (show day)
| sob == 'B' = "Bought " ++ (show unit) ++ " units of " ++ (show stock) ++ " for " ++ (show price) ++ " pounds each on day " ++ (show day)
Where Transaction is a custom data type - Transaction = (Char, Int, Int, String, Int)
Error:
Parse error in pattern: transaction_to_string
|
23 | transaction_to_string (sob : unit : price : stock : day) :: Transaction
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

There are several syntax errors in your code example.
try this instead:
type Transaction = (Char, Int, Int, String, Int)
transaction_to_string :: Transaction -> String
transaction_to_string (sob, unit, price, stock, day)
| sob == 'S' = "Sold" ++ (show unit) ++ " units of " ++ (show stock) ++ " for " ++ (show price) ++ " pounds each on day " ++ (show day)
| sob == 'B' = "Bought " ++ (show unit) ++ " units of " ++ (show stock) ++ " for " ++ (show price) ++ " pounds each on day " ++ (show day)

Related

Function expects Char in place of [Char]

I am new to Haskell and functional programming, and can't understand why this function cannot identify the correct type:
mformat :: [Char] -> [Char] -> [Char]
mformat first last = ((formatted first last) ++ " " ++ first ++ " " ++ last ++ ".")
where formatted (f:_) (l:_) = (f ++ "." ++ l ++ ".")
which causes the error:
teststuff.hs:42:40: error:
* Couldn't match type `Char' with `[Char]'
Expected: [[Char]]
Actual: [Char]
* In the second argument of `formatted', namely `last'
In the first argument of `(++)', namely `(formatted first last)'
In the expression:
(formatted first last) ++ " " ++ first ++ " " ++ last ++ "."
|
42 | mformat first last = ((formatted first last) ++ " " ++ first ++ " " ++ last ++ ".")
| ^^^^
Failed, no modules loaded.
I don't understand what is wrong here, any help would be appreciated.
The issue is in your formatted function. You are pattern matching on a String, you get Chars (f & l) and then you try concatenating them with a String. You cannot concatenate a Char with a String ([Char]).
mformat :: String -> String -> String
mformat first last = ((formatted first last) ++ " " ++ first ++ " " ++ last ++ ".")
where
formatted :: String -> String -> String
formatted (f:_) (l:_) = ([f] ++ "." ++ [l] ++ ".")
or
-- ...
formatted (f:_) (l:_) = (f : "." ++ l : ".")
The type checker thinks thinks that f and l in your case must be lists - because you are attempting to concatenate them. Then it infers (via pattern matching) from the list constructor, that first and last are lists of Strings i.e. [String] or [[Char]].

Haskell : list comprehension

How can I write this code without repeating (c !! x) where is x = [0..7], using list comprehension is better but I couldn't figure how to write it
show (EOBoard f c r) = "EOBoard\n" ++ "Foundations "
++ show f ++ "\n" ++ "Columns \n"
++ show (c!!0) ++ "\n" ++ show (c!!1) ++ "\n"
++ show (c!!2) ++ "\n" ++ show (c!!3) ++ "\n"
++ show (c!!4) ++ "\n" ++ show (c!!5) ++ "\n"
++ show (c!!6) ++ "\n" ++ show (c!!7) ++ "\n"
++ "Reserves " ++ show r
Let's start by getting rid of all those manual line breaks.
import Data.List
show (EOBoard f c r) = intercalate "\n" $
[ "EOBoard"
, "Foundations " ++ show f
, "Columns"
, show (c!!0)
, show (c!!1)
, show (c!!2)
, show (c!!3)
, show (c!!4)
, show (c!!5)
, show (c!!6)
, show (c!!7)
, "Reserves " ++ show r]
Note: if you want a line break at the end too, use unlines instead of intercalate.
As you noticed, there's a rather repetitive section. Also, those !! applications are kind of expensive. A list comprehension solves both problems, but I'd use map instead.
show (EOBoard f c r) = intercalate "\n" $
[ "EOBoard"
, "Foundations " ++ show f
, "Columns" ] ++
map show c ++
["Reserves " ++ show r]
(map show c could be replaced by [show x | x <- c] if you prefer.)
There's still something funny; Show really isn't for pretty-printing. show shouldn't insert line breaks. You probably actually want to write a custom pretty-printing function instead.
What you wrote is equivalent to
show (EOBoard f c r) = "EOBoard\n" ++ "Foundations "
++ show f ++ "\n" ++ "Columns \n" ++
++ concat [ show s ++ "\n" | s <- take 8 c]
++ "\n" ++ "Reserves " ++ show r
which is equivalent to
show (EOBoard f c r) = "EOBoard\n" ++ "Foundations "
++ show f ++ "\n" ++ "Columns \n" ++
++ [ ch | s <- take 8 c, ch <- show s ++ "\n" ]
++ "\n" ++ "Reserves " ++ show r
or, using the concat more instead of inlining it, it is equivalent to
show (EOBoard f c r) = concat (
[ "EOBoard\n", "Foundations ", show f, "\n", "Columns \n" ]
++ [ show s ++ "\n" | s <- take 8 c]
++ ["\n" , "Reserves " , show r] )
which is normally written with the $ operator, as
show (EOBoard f c r) = concat $
[ "EOBoard\n", "Foundations ", show f, "\n", "Columns \n" ]
++ [ show s ++ "\n" | s <- take 8 c]
++ ["\n" , "Reserves " , show r]

New line in haskell IO

I am not able to print outputs in multiple lines with the following code.
average l = (sum l) / (fromIntegral (length l))
readDoubles s1 s2 = putStr (s1++"\n"++s2) >>
do x <- readDoublesHelper; return ("The average is " ++ (show (average x)) ++ " \n" ++ "The maximum is " ++ (show (maximum x)) ++ "\n" ++ "The minimum is " ++ (show (minimum x)) ++ "\n")
readDoublesHelper = putStr "Enter a number: " >>
do line <- getLine;
if line == "done"
then return [];
else do xs <- (readDoublesHelper)
return ((read line :: Float): xs)
interface = readDoubles "Enter some numbers." "When finished, type ’done’. \n"
The output that I get is
*Main> interface
Enter some numbers.
When finished, type ’done’.
Enter a number: 2
Enter a number: 3
Enter a number: 4
Enter a number: 5
Enter a number: 6
Enter a number: 7
Enter a number: done
"The average is 4.5 \nThe maximum is 7.0\nThe minimum is 2.0\n"
But I want the output to be printed like this
The average is 4.5
The maximum is 7.0
The minimum is 2.0
Do notice "The average is 4.5 \nThe maximum is 7.0\nThe minimum is 2.0\n" is actually not printed
Reformatting readDoubles:
readDoubles s1 s2 = do
putStr (s1++"\n"++s2)
x <- readDoublesHelper
return ("The average is " ++ (show (average x)) ++ " \n" ++ "The maximum is " ++ (show (maximum x)) ++ "\n" ++ "The minimum is " ++ (show (minimum x)) ++ "\n")
We can see that result is "returned" rather than "printed"
As the type signature of readDoubles is:
readDoubles :: String -> String -> IO String
It just returns a lifted string. Since GHCi will print out the final result of the function, you're getting "The average is 4.5 \nThe maximum is 7.0\nThe minimum is 2.0\n" as output (the return value of the function)
However, from you description, I guess you just like to print out the result, so it should be:
readDoubles :: String -> String -> IO ()
readDoubles s1 s2 = do
putStr (s1++"\n"++s2)
x <- readDoublesHelper
putStrLn ("The average is " ++ (show (average x)) ++ " \n" ++ "The maximum is " ++ (show (maximum x)) ++ "\n" ++ "The minimum is " ++ (show (minimum x)) ++ "\n")

How are expressions allowed inside Haskell do blocks

In the following code, line 4, I have an expression sandwiched between two IO actions in a do block:
1 doubleX :: (Show x, Num x) => x -> IO ()
2 doubleX x = do
3 putStrLn ("I will now double " ++ (show x))
4 let double = x * 2
5 putStrLn ("The result is " ++ (show double))
I understand do notation as chaining monadic operations together using >>= or >>. But how does that work when you have an expression in between? You couldn't just glue lines 3-5 together using >>.
I'm going to crib from my very similar answer here (though probably not a duplicate since that question doesn't explicitly deal with let).
The Report gives a full translation from do syntax into kernel Haskell; the parts relevant to your question are:
do {e} = e
do {e;stmts} = e >> do {stmts}
do {let decls; stmts} = let decls in do {stmts}
So your code desugars like this:
doubleX x = do
putStrLn ("I will now double " ++ (show x))
let double = x * 2
putStrLn ("The result is " ++ (show double))
==> do {e;stmts} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >> do
let double = x * 2
putStrLn ("The result is " ++ (show double))
==> do {let decls; stmts} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >>
let double = x * 2 in do
putStrLn ("The result is " ++ (show double))
==> do {e} rule
doubleX x =
putStrLn ("I will now double " ++ (show x)) >>
let double = x * 2 in
putStrLn ("The result is " ++ (show double))

Error when using RecordWildCards extension from GHCi

I have created a function that uses the RecordWildCards syntax for pattern matching on a Haskell record type:
Pragmas
I have placed the pragmas at the top of the file. I have also tried adding it with :set -XRecordWildCards.
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE RecordWildCards #-}
Type definitions
data ClientR = GovOrgR { clientRName :: String }
| CompanyR { clientRName :: String,
companyId :: Integer,
person :: PersonR,
duty :: String
}
| IndividualR { person :: PersonR }
deriving Show
data PersonR = PersonR {
firstName :: String,
lastName :: String
} deriving Show
Function
greet2 :: ClientR -> String
greet2 IndividualR { person = PersonR { .. } } = "hi" ++ firstName ++ " " ++ lastName + " "
greet2 CompanyR { .. } = "hello " ++ firstName ++ " " ++ lastName ++ "who works as a " ++ duty ++ " " ++ clientRName + " "
greet2 GovOrgR {} = "Welcome"
Error
• Couldn't match expected type ‘[Char]’
with actual type ‘PersonR -> String’
• Probable cause: ‘lastName’ is applied to too few arguments
In the first argument of ‘(++)’, namely ‘lastName’
In the second argument of ‘(++)’, namely
‘lastName ++ "who works as a " ++ duty ++ " " ++ clientRName + " "’
In the second argument of ‘(++)’, namely
‘" "
++
lastName ++ "who works as a " ++ duty ++ " " ++ clientRName + " "’
Failed, modules loaded: none.
When I use this function on CompanyR to match the PersonR using as pattern, I get:
Function
greet2 c#(CompanyR { .. }) = "hello " ++ (firstName $ person c) ++ " " ++ (lastName $ person c)
Error
Couldn't match expected type ‘ClientR -> PersonR’
with actual type ‘PersonR’
• The function ‘person’ is applied to one argument,
but its type ‘PersonR’ has none
In the second argument of ‘($)’, namely ‘person c’
In the first argument of ‘(++)’, namely ‘(firstName $ person c)’
• Couldn't match expected type ‘ClientR -> PersonR’
with actual type ‘PersonR’
• The function ‘person’ is applied to one argument,
but its type ‘PersonR’ has none
In the second argument of ‘($)’, namely ‘person c’
In the second argument of ‘(++)’, namely ‘(lastName $ person c)’
You do it right in your first case here (although I fixed a ++ where you had +):
greet2 :: ClientR -> String
greet2 IndividualR { person = PersonR { .. } } = "hi" ++ firstName ++ " " ++ lastName ++ " "
But here firstName etc are not records in CompanyR so CompanyR { .. } does not bring them into scope:
greet2 CompanyR { .. } = "hello " ++ firstName ++ " " ++ lastName ++ "who works as a " ++ duty ++ " " ++ clientRName + " "
You have to do something like you did in the first case of greet2, just above:
greet2 CompanyR {person = PersonR { .. }, .. } = "hello " ++ firstName ++ " " ++ lastName ++ "who works as a " ++ duty ++ " " ++ clientRName ++ " "

Resources