basic Haskell : list comprehension - haskell

Me again, I'm trying to iterate through my list of customers to find the correct customer and when I find them I want to display any non-zero int's that are attached to them. I'm not sure how to proceed. I know there will only be 1 record of the person's name in the shop.
type Name = String
type Customer = (Name,Int,Int)
type Shop = [Customer]
shop = [cust1, cust2]
cust1 = ("Steve", 321, 123) :: Customer
cust2 = ("John", 0,678) :: Customer
getName :: Customer -> Name
getName (a, b,c) = a
getNumbers :: Customer -> [Int]
getNumbers (a,b,c) = filter (/=0) [b,c]
rental:: Shop-> Name -> [Int]
rental shop' name' = map getNumbers [ x|x<-shop',getName x == name']

It is very useful to read error message!
test23.hs:10:9:
Couldn't match type `(Name, t0)' with `(Name, Int, Int)'
Expected type: Customer
Actual type: (Name, t0)
You have
getName (a, b) = a
but is defined
type Customer = (Name,Int,Int)
The right function looks like
getName (a, _, _) = a
After correct, you could see next meassage:
test23.hs:17:26:
Couldn't match type `[Int]' with `Int'
Expected type: Customer -> Int
Actual type: Customer -> [Int]
In the first argument of `map', namely `getNumbers'
...
In an equation for `rental'
But error is not in getNumbers, but in signature of rental:: Shop-> Name -> [Int]. Must be:
rental:: Shop-> Name -> [[Int]]

Your answer is pretty close. First of all, you need to update getName to take a 3-tuple, and second you should use concatMap getNumbers instead of map getNumbers.
Although, it looks like you're going to be adding new fields to your Customer type, so I would recommend that you switch to using a record instead:
data Customer = Customer
{ custName :: Name
, custVal1 :: Int -- I don't know what these are, so use real names
, custVal2 :: Int
} deriving (Eq, Show)
And now you could get rid of getName and do
getNumbers :: Customer -> [Int]
getNumbers c = filter (/= 0) [custVal1 c, custVal2 c]
rental :: Shop -> Name -> [Int]
rental shop' name' = concatMap getNumbers [x | x <- shop', custName x == name']
Now if you were to add another field to Customer, you don't have to update all your functions that don't depend on that field.

Related

Defining a High Order function that acesses data records

I pretend to create a high order function that uses as one of its parameters a function which belongs to the record of a certain Data Type.
For Example:
type Debt = Float
type Power = Int
Data State = S String Debt
Data City = C String Power Debt
Data Country = Country
{ states :: [State]
, cities :: [City] }
upDetail :: (Country -> [a])
-> ([a] -> b -> [a])
-> b -> Country -> Country
upDetail f g b country = country { f = new }
where old = f country
new = g old b
What the function above is supposed to do is pick an element of the record of the Country (with the function type Country -> [a]) and alter it according to a certain function type [a] -> b -> [a] and a certain b
However, when i try to compile this i get an error saying :
‘f’ is not a (visible) constructor field name
Is there any way i can overcome this problem? I thought of using Maybe Country as my result but i don't know how to do this.
As the comments mention, the normal solution to this is to use lenses:
upDetail :: Lens Country [a]
-> ([a] -> b -> [a])
-> b -> Country -> Country
upDetail f g b country = set f country new
where old = get f country
new = g old b
However, lenses aren't that hard to get a handle on, especially for so simple a purpose.
The simplest way of expressing a lens is as a getter and a setter function:
data Lens s a = Lens
{ get :: s -> a
, set :: s -> a -> s
}
_states :: Lens Country [State]
_states = Lens states $ \c new -> c { states = new }
_cities :: Lens Country [City]
_cities = Lens cities $ \c new -> c { cities = new }
This lets us modify the cities or states of a country pretty easily:
λ Country [] []
Country {states = [], cities = []}
λ upDetail _cities (\cs c -> c:cs) (C "Hereford" 100 3000) it
Country {states = [], cities = [C "Hereford" 100 3000.0]}
λ upDetail _states (\cs c -> c:cs) (S "Delmarva" 4) it
Country {states = [S "Delmarva" 4.0], cities = [C "Hereford" 100 3000.0]}
Lens get slightly more complex once you start thinking about composing lenses, which you're not getting into here, but you could.

Haskell lookup table to return functions

Trying to extend "The Maybe monad" example on this page. Their lookup table phonebook:
phonebook :: [(String, String)]
phonebook = [ ("Bob", "01788 665242"),
("Fred", "01624 556442"),
("Alice", "01889 985333"),
("Jane", "01732 187565") ]
and there chained monad examples:
getRegistrationNumber :: String -- their name
-> Maybe String -- their registration number
getRegistrationNumber name =
lookup name phonebook >>=
(\number -> lookup number governmentalDatabase)
What happens if we want to return a function (that then returns a specific type) instead? So extending from their example, instead of looking up a registration number, we want to lookup lookup either their age, their ZIP, or the years that there property taxes were paid. Given these examples, an INT seems appropriate for the first two, and a List of Ints for the last. FIRST Question: since the lookup table has a type, must all of the return types of the functions be of the same type? I am assuming yes, but am unsure, hence the next question.
lets say that we write these 'finding' functions that return the same type [Int]. Maybe something like these:
getAge :: String -> Maybe [Int]
getAge phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalAgeDatabase)
getZip :: String -> Maybe [Int]
getZip phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalZipCodeDatabase)
getTaxPaidYears :: String -> Maybe [Int]
getTaxPaidYears phoneNumberString =
lookup name phonebook >>==
(\phoneNumberString -> lookup phoneNumberString governmentalTaxYearDatabase)
Now, assuming each of the the *Databases return an [Int] type, Second Question How do we write ONE function like lookupPersonsInformation that would return the appropriate information from what's typed in the input String, and given a lookup that returns the appropriate function, returns the information requested? Here is what I am trying to make work:
lookupAppropriateFunction :: [(String, String -> [Int])] --Here I want the second part
-- of the tuple to be the functions
lookupAppropriateFunction = [ ("age", getAge),
("zip", getZip),
("taxes", getTaxPaidYears) ]
lookupPersonsInformation :: String -> Maybe [Int]
lookupPersonsInformation nameAndInfo =
lookup ( words nameAndInfo!!0 ) >>=
( \phoneNumberString -> lookup ( words nameAndInfo!!1 ) lookupAppropriateFunction )
-- >> lookupPersonsInformation "Bob age"
[53] --Bob's age
-- >> lookupPersonsInformation "Fred zip"
[28202] --Fred's age
-- >> lookupPersonsInformation "Alice taxes"
[2010,2011,2013] --Alice's paid taxes years, It looks like she skipped 2012 :)
It is apparent that the errors propagate through to the end as Nothing, but I am unsure how to take the next step in applying this to a higher order function. Is it more in the parsing using words or in the structure of the lookup table that I want to return a function`
I ended up with going with something like the following:
-------------------------------------------------------------------------
intPusher :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and tries to turn it into an Int, and push it onto the stack
intPusher word = case (reads word) of
[] -> \stak -> Nothing
[(x,"")] -> \stak -> Just (x:stak)
[(x,y)] -> \stak -> Nothing
-------------------------------------------------------------------------
dicLookup :: String -> Stack -> Maybe Stack
-- ^ Takes a word, and looks it up in the dictionary
dicLookup word = case (lookup word wordsTable) of
Nothing -> intPusher word
Just f -> f
-------------------------------------------------------------------------
wordsTable :: [(String, Stack -> Maybe Stack)]
-- ^ Checks the string against the commands
wordsTable = [ ("+", addIt)
,("-", subIt)
,("*", multIt)
,("/", divIt)
,("/MOD", modQuotIt)
,("MOD", modIt)
....
,("2DROP", drop2It) ]
-------------------------------------------------------------------------
interpretProgram :: String -> Maybe Stack
interpretProgram str = foldl (>>=) (Just[]) (map dicLookup (words str))
and for each tuple value in the dictionary, I provided the function declaration:
-------------------------------------------------------------------------
addIt :: Stack -> Maybe Stack
-- ^ Adds the first two elements of the stack
addIt stak = case stak of
x:y:xs -> Just (x + y:xs)
x:xs -> Nothing
_ -> Nothing
-------------------------------------------------------------------------
subIt :: Stack -> Maybe Stack
-- ^ Subtracts the first two elements of the stack
subIt stak = case stak of
x:y:xs -> Just (y - x:xs)
x:xs -> Nothing
_ -> Nothing
-------------------------------------------------------------------------
multIt :: Stack -> Maybe Stack
-- ^ Multiplies the first two elements of the stack
multIt stak = case stak of
x:y:xs -> Just (x * y:xs)
x:xs -> Nothing
_ -> Nothing
...
This works by taking a string, breaking it into individual 'words' (if possible, and returning Nothing if it can't) that are then passed into a dictionary to lookup the value of the word compared to the keys in the dictionary, thus acting like a lookup table. If the word is a key in the dictionary, it returns the value, which is a higher order function that does certain tasks (just like the words function, if the higher order function encounters an error, it will return Nothing).
When dealing with Monads, there are only TWO types of return values. Maybe AnyType and Nothing. An AnyType can be any type already declared in the module, or any basic type in Haskell (Int, Char, [Char], etc...). The trick is to return either a Maybe AnyType or a Nothing type. Since Haskell requires terminal declaration for if statements, it can be convention to 'catch' any potential errors and pass along the 'Nothing' type to the final return of a [grand]parent function.

basic haskell: error with simple function

I'm not sure what is wrong with my code, but when I try and run it I get
Couldn't match type `Integer' with `Int'
I'm using GHCi. I want to create a basic program that will go through the shop and give me all the customer names so I can then do a search to find out what item they have rented (a library). Is there a better way of getting the names?
This is my code:
type Name = String
type Customer = (Name,Int)
type shop = [Customer]
shop = [cust1, cust2]
cust1 = ("Neil", 311)
cust2 = ("Fred", 0)
getName :: (String,Int) -> Name
getName (a,b) = a
GHCi will default to using Integer over Int. You should specify the type of your tuples as cust1 = ("Neil", 311 :: Int) or cust2 = ("Fred", 0) :: (String, Int).
Edit after updates
If you already have Customer defined, you should write it as
cust1 = ("Neil", 311) :: Customer
cust2 = ("Fred", 0) :: Customer
getName :: Customer -> Name
getName (a, b) = a
You could also simplify things a bit by defining getName as
getName :: Customer -> Name
getName = fst
using ETA reduction and the built-in function fst

Errorhandling and monads?

I'm trying to understand how to apply the Maybe-idiom from Haskel.. I'm reading http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe which shows that a lookup in a dictionary may return a Maybe and that this value propates through the >>= operator.
The example from the URL:
If we then wanted to use the result from the governmental database lookup in a third lookup (say we want to look up their registration number to see if they owe any car tax), then we could extend our getRegistrationNumber function:
getTaxOwed :: String -- their name
-> Maybe Double -- the amount of tax they owe
getTaxOwed name =
lookup name phonebook >>=
(\number -> lookup number governmentalDatabase) >>=
(\registration -> lookup registration taxDatabase)
Or, using the do-block style:
getTaxOwed name = do
number <- lookup name phonebook
registration <- lookup number governmentalDatabase
lookup registration taxDatabase
Question:
How do I deal with error handling? I think most code will benefit from telling where things went wrong. Rather than just reporting "couldn't find John Doe in either phonebook or governmentalDatabase" it should report which ressource had problems.
You could use the monad instance for Either String, which is essentially defined as
instance Monad (Either String) where
fail msg = Left msg
return x = Right x
Left msg >>= k = Left msg
Right x >>= k = k x
(The actual definition is a bit more involved.)
If we then define dictionaries as pairs consisting of a label and a lookup table
type Dict a b = (String, [(a, b)])
phonebook' :: Dict String Int
phonebook' = ("phone book", phonebook)
governmentalDatabase' :: Dict Int Int
governmentalDatabase' = ("governmental database", governmentalDatabase)
taxDatabase' :: Dict Int Double
taxDatabase' = ("tax database", taxDatabase)
where phonebook, governmentalDatabase, and taxDatabase are as you had them defined before, we can use an alternative monadic lookup function that returns its result in the Either String-monad:
lookup' :: (Eq a, Show a) => a -> Dict a b -> Either String b
lookup' key (descr, table) = case lookup key table of
Nothing -> Left ("couldn't find " ++ show key ++ " in " ++ descr)
Just val -> Right val
Illustrating the power of monads, the only thing that now needs to change in your client function is the type signature:
getTaxOwed :: String -- their name
-> Either String Double -- either an error message
-- or the amount of tax they owe
getTaxOwed name = do
number <- lookup' name phonebook'
registration <- lookup' number governmentalDatabase'
lookup' registration taxDatabase'
Running this function on an unknown name gives:
> getTaxOwed "Joe"
Left "couldn't find \"Joe\" in phone book"
The Maybe data type has only the value "Nothing" for signaling an error. If you want to return a specific error message i suggest the data type "Either", which can return either a "Left a" or "Right a" value. Read more about how to use that at http://learnyouahaskell.com/for-a-few-monads-more#error

Confused about custom data types in Haskell

The task: I am trying to create a custom data type and have it able to print to the console. I also want to be able to sort it using Haskell's natural ordering.
The issue: Write now, I can't get this code to compile. It throws the following error: No instance for (Show Person) arising from a use of 'print'.
What I have so far:
-- Omitted working selection-sort function
selection_sort_ord :: (Ord a) => [a] -> [a]
selection_sort_ord xs = selection_sort (<) xs
data Person = Person {
first_name :: String,
last_name :: String,
age :: Int }
main :: IO ()
main = print $ print_person (Person "Paul" "Bouchon" 21)
You need a Show instance to convert the type to a printable representation (a String). The easiest way to obtain one is to add
deriving Show
to the type definition.
data Person = Person {
first_name :: String,
last_name :: String,
age :: Int }
deriving (Eq, Ord, Show)
to get the most often needed instances.
If you want a different Ord instance, as suggested in the comments, instead of deriving that (keep deriving Eq and Show unless you want different behaviour for those), provide an instance like
instance Ord Person where
compare p1 p2 = case compare (age p1) (age p2) of
EQ -> case compare (last_name p1) (last_name p2) of
EQ -> compare (first_name p1) (first_name p2)
other -> other
unequal -> unequal
or use pattern matching in the definition of compare if you prefer,
compare (Person first1 last1 age1) (Person first2 last2 age2) =
case compare age1 age2 of
EQ -> case compare last1 last2 of
EQ -> compare first1 first2
other -> other
unequal -> unequal
That compares according to age first, then last name, and finally, if needed, first name.

Resources