Manipulating a value within several layers of monads - haskell

My goal is to pull out numVal4 from Employment -- but doing it from the level of the MyEmployment value.
data Employment = Employment
{ textVal1 :: Text
, textVal2 :: Text
, textVal3 :: Text
, numVal4 :: Money }
data MyEmployment = MyEmployment Person Employment
MyEmployment (Person "Me") (Employment "This" "is a" "test" 55)
fmap . fmap (fromInteger (Employment _ _ _ x)) MyEmployment
EDIT:
I should have bee more specific. I need to access the value from within a DMap. The actual code looks like something closer to this:
thing = dmap ! (Some_Function . Some_OtherFunction $ MyEmployment)
And I need to get the numeric value from inside of Employment, with some kind of wrapper like:
thing = fmap (fromIntegral (Employment _ _ _ x)) (dmap ! (Some_Function . Some_OtherFunction $ MyEmployment)

Apart from all the syntax issues, I think what you are trying to do is the following.
This is how you declare a data type:
data Employment = Employment
{ textVal1 :: Text
, textVal2 :: Text
, textVal3 :: Text
, numVal4 :: Money }
Note the ::s which are not =, and note the indentation.
MyEmployment seems to be a data type and by MyEmployment :: Person Employment I think you in fact mean
data MyEmployment = MyEmployment Person Employment
In this setting then, If you want to take a value of type MyEmployment, and apply a function to the numVal4 field of the Employment field, record syntax allows you to write:
foo :: (Money -> Money) -> MyEmployment -> MyEmployment
foo f (MyEmployment p e#(Employment {numVal4 = nv}))
= MyEmployment p ( e {numVal4 = f nv})

Related

understanding cyclic/recursive data types in haskell

I'm trying to fully understand haskell's data types, so I created these:
data District = District {nameOfCity :: String,
subDistricts ::[DistrictUnit]}
deriving (Show, Eq)
data DistrictUnit = DistrictUnit District
| BranchUnit Branch
deriving (Show, Eq)
data Branch = Branch {nameOfBranch :: String,
numOfEmployees :: Int,
sales :: Int}
deriving (Show, Eq)
Here are some examples:
a = District {nameOfCity = "Berlin", subDistrcits = []}
b = District {nameOfCity = "New York",
subDistricts =
[DistrictUnit
(District {nameOfCity = "Amsterdam",
subDistricts =
[DistrictUnit
(District {nameOfCity = "London",
subDistricts = []})]})]}
c = District {nameOfCity = "Iowa" ,
subDistricts =
[BranchUnit
(Branch {nameOfBranch = "Omaha",
numOfEmployees = 3,
sales = 2343})]}
Now I'm trying to build two functions: getNameOfCity and getNameOfBranch:
getNameOfCity b -> ["New York", "Amsterdam", "London"]
But I have massive pattern matching issues. I just don't know how to build a function that works for all inputs.
Here are my attempts:
getNameOfCity :: District -> [String]
getNameOfCity (District a b) = [a]
This function will only give me the first name:
["New York"]
So I tried this:
getNameOfCity (District a [DistrictUnit (District b c)]) = [a, b]
And (of course) that one will only give me the first two names:
["New York", "Amsterdam"]
How can I make that getNameOfCity work for all inputs? And will getNamesOfBranch work the same way (since it has different parameters)? Thank you in advance :)
Rather than trying to do everything with a single function, it's easier to write separate helpers:
allDistrictNames :: District -> [String] -- This was your `getNameOfCity`
allDistrictNames_u :: DistrictUnit -> [String]
allDistrictNames_ul :: [DistrictUnit] -> [String]
allDistrictNames and allDistrictNames_u can now be implemented with simple pattern matches and calls to each other. allDistrictNames_ul needs to call allDistrictNames_u on all list elements, and combine the results. There's a standard function for this exact purpose.
You want getNameOfCity applied to a District to return its nameOfCity field, prepended to the list of city names from each of its subDistricts that are Districts and not Branches.
So you had a good starting point with something like this:
getNameOfCity :: District -> [String]
getNameOfCity (District name units) = [name]
But of course you need to do something with units. The pattern you wrote in your second example, [DistrictUnit (District b c)], only matches when the subDistricts field contains a list of exactly one element, where that element is also a DistrictUnit, and extracts only the nameOfCity field (b) from that district, ignoring any further nested subdistricts (in c).
To help you with this, I’m going to give you a template for you to fill in, following a common pattern that’s very helpful when you’re getting familiar with Haskell: working back from the desired result, breaking down the problem into small steps, and giving each step a name and a type signature. That way, if you make a mistake, the compiler will produce much more comprehensible error messages. Then, once you have a working solution, you can remove the intermediate variables and consolidate the steps into a more compact expression.
First, your desired result is the root district name prepended to the list of names of all subdistricts.
getNameOfCity :: District -> [String]
getNameOfCity (District name units) = let
allCities :: [String]
allCities = …
in name : allCities
To construct this, you’ll need to iterate over the units and extract the names from each district, then concatenate all the results.
getNameOfCity :: District -> [String]
getNameOfCity (District name units) = let
districtCities :: [[String]]
districtCities = … -- List of list of city names for each ‘District’
allCities :: [String]
allCities = … -- Concatenated ‘districtCities’
in name : allCities
The iteration over the units can be done in a few ways, but what I would do is extract only the Districts first so you have a narrower, more precise type to work with, and then you can simply apply getNameOfCity recursively on them.
getNameOfCity :: District -> [String]
getNameOfCity (District name units) = let
-- Extract only those ‘units’ that are ‘District’s
districts :: [District]
districts = …
-- Hint:
-- Hoogle ‘(a -> Maybe b) -> [a] -> [b]’
-- and define ‘getDistrict :: DistrictUnit -> Maybe District’;
-- or use a list comprehension of the form: ‘[… | … <- units]’
districtCities :: [[String]]
districtCities = …
allCities :: [String]
allCities = …
in name : allCities
You could follow a very similar approach for the branch names; it’s a good exercise to consider how you might abstract over the commonalities, once you have both of them in front of you.
It’s also a common higher-level approach to solve this sort of problem using the Semigroup & Monoid typeclasses, which are mathy names for the sets of types that can be “appended” associatively in some way (the <> operator), and have a default “empty” value (mempty) which is a no-op for appending. The general method is to map each value to a “summary” value—here, the list of city names—and then fold those summaries together, conveniently combined into a single operation called foldMap. For instance:
districtCities :: District -> [String]
districtCities (District city units) = [city] <> foldMap unitCities units
unitCities :: DistrictUnit -> [String]
-- Recursively summarise district.
unitCities (DistrictUnit district) = districtCities district
-- Return “empty” value for branch.
unitCities (BranchUnit branch) = mempty
This generalises to accumulating other fields, like the branch names:
districtBranches :: District -> [String]
districtBranches (District _ units) = foldMap unitBranches units
unitBranches :: DistrictUnit -> [String]
unitBranches (DistrictUnit district) = districtBranches district
unitBranches (BranchUnit branch) = [nameOfBranch branch]
Or other types of values, like the total sales, using the Sum monoid:
import Data.Monoid (Sum(..))
totalSales :: District -> Int
totalSales district = getSum (districtSales district)
-- Or: totalSales = getSum . districtSales
districtSales :: District -> Sum Int
districtSales (District _ units) = foldMap unitSales units
unitSales :: DistrictUnit -> Sum Int
unitSales (DistrictUnit district) = foldMap districtSales district
unitSales (BranchUnit branch) = Sum (branchSales branch)
Or even multiple values at once, using e.g.: (Sum 1, ["London"]) <> (Sum 2, ["Paris"]) = (Sum 3, ["London", "Paris"]). Notice how all these implementations have similar structure, too, though, and consider how you might abstract over this “folding” pattern generically.

Datatype Person mother from mother (grandmother)

Imagine I've got a datatype Person.
data Person = Person String Person
The 2. Person should be the mother.
showGrandmother :: Person -> Maybe Person
showGrandmother (Person _ mother) = Just mother
Will only show the mother from person x.
How can I show the grandmother?
first, your data definition is missing the base case. Assuming this represents matrilineality, I would start with Eve as the base case
data Person = Eve | Person String Person deriving (Show)
defining mother function
mother Eve = Nothing
mother (Person _ m) = Just m
now grandmother is applying this twice
grandmother = \x -> mother x >>= mother
With Control.Monad Kleiski operators, this can be written much nicely
grandmother = mother >=> mother
With pattern matching, you aren't limited to one level of constructors, you can nest them to go further "in":
showGrandmother :: Person -> Maybe Person
showGrandmother (Person _ (Person _ grandmother)) = Just grandmother
As a sidenote, I'm not a Haskell expert, but it seems like the data type is a bit circular for what is meant to be a model of a family tree. You can't actually create a person without it referencing another person. Maybe something better would be...
data Person = Person String (Maybe Person)
... in which case, finding the grandmother can be done as...
showGrandmother :: Person -> Maybe Person
showGrandmother (Person _ Just (Person _ (Just grandmother)))) = Just grandmother
showGrandmother _ = Nothing
... making sure to handle the base case when someone doesn't have a grandmother. Your original type didn't need to handle this case because everyone must have a grandmother according to it.
And taking inspiration from the #Karafka's answer, it's possible to factor out finding the mother of a person...
showMother :: Person -> Maybe Person
showMother (Person _ (Just mother)) = Just mother
showMother _ = Nothing
... and using the fact that Maybe is a monad, can use it as below.
showGrandmother :: Person -> Maybe Person
showGrandmother x = showMother x >>= showMother
I suspect understanding the above monadic code would be out of scope for this particular question.

basic Haskell : list comprehension

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.

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

Haskell introspecting a record's field names and types

Based on a recent exchange, I've been convinced to use Template Haskell to generate some code to ensure compile-time type safety.
I need to introspect record field names and types. I understand I can get field names by using constrFields . toConstr :: Data a => a -> [String]. But I need more than the field names, I need to know their type. For example, I need to know the names of fields that are of type Bool.
How do I construct a function f :: a -> [(String, xx)] where a is the record, String is the field name and xx is the field type?
The type should be available, along with everything else, in the Info value provided by reify. Specifically, you should get a TyConI, which contains a Dec value, from which you can get the list of Con values specifying the constructors. A record type should then use RecC, which will give you a list of fields described by a tuple containing the field name, whether the field is strict, and the type.
Where you go from there depends on what you want to do with all this.
Edit: For the sake of actually demonstrating the above, here's a really terrible quick and dirty function that finds record fields:
import Language.Haskell.TH
test :: Name -> Q Exp
test n = do rfs <- fmap getRecordFields $ reify n
litE . stringL $ show rfs
getRecordFields :: Info -> [(String, [(String, String)])]
getRecordFields (TyConI (DataD _ _ _ cons _)) = concatMap getRF' cons
getRecordFields _ = []
getRF' :: Con -> [(String, [(String, String)])]
getRF' (RecC name fields) = [(nameBase name, map getFieldInfo fields)]
getRF' _ = []
getFieldInfo :: (Name, Strict, Type) -> (String, String)
getFieldInfo (name, _, ty) = (nameBase name, show ty)
Importing that in another module, we can use it like so:
data Foo = Foo { foo1 :: Int, foo2 :: Bool }
foo = $(test ''Foo)
Loading that in GHCi, the value in foo is [("Foo",[("foo1","ConT GHC.Types.Int"),("foo2","ConT GHC.Types.Bool")])].
Does that give you the rough idea?

Resources