Hello i do not understand why i do have the following problem :
I am trying to define taxes definition for Company using taxes implementation from Employee.I do not understand why i face the following errors:
data Employee=Employee{
age::Int,
name::String,
job::Job,
wage::Double
}
data Job= Worker | Manager |Unemployed deriving(Eq,Ord,Show)
data Company=Company{
compName::String,
year::Int,
employees::[Employee]
}
class Charges a where
taxes::a->Double
instance Charges Employee where
taxes Employee{age=a,wage=w}=fromIntegral a * w
Implementation 1:
instance Charges Company where
taxes comp=foldl ((+).taxes) 0 employees
Error:
Couldn't match type `[Employee]' with `Double'
Expected type: Company -> Double
Actual type: Company -> [Employee]
Why is it a problem since i take an Employee one by one i apply taxes which is already implemented for Employee and i add it to the counter??
Implementation2 - using foldr
instance Charges Company where
taxes comp =foldl ((+).taxes) 0 (employees comp)
Error:
Couldn't match expected type `Company -> Double'
with actual type `Double'
* Possible cause: `foldr' is applied to too many arguments
I see no more then 3 arguments what is the problem?
There is already a function in the Prelude that is excellent for summing lists of numbers. Why are we reinventing summation with a fold? Break the problem down into a few parts:
Find the company's employees
Compute taxes for each
Sum the results
Thus:
instance Charges Company where
taxes = sum . map taxes . employees
Related
I'm writing a Car data type as an extension to an example: data Car = Car{customers::[a]} where customers::[a] is to show a list of customers who are riding the car. Then I have written a function of ListCustomer to store a list of all customers by converting the data from data set into a list.
I have written :
ListCustomer::Car->[a]
ListCustomer (Car{customers = [a]}) = [a]
and there is parsing error in the brackets. I have checked the brackets and they appear balanced.
What the compiler is telling you is that it doesn't understand the function you're declaring, since functions in Haskell have to start with a lower case letter. This compiles:
listCustomer :: Car a -> [a]
listCustomer (Car{customers = [a]}) = [a]
I should add that this will throw a "non-exhaustive pattern" error if you use it with inputs like Car [1,2] or Car [], since Haskell interprets the pattern customers = [a] as "a list of one element in the customers field". One way to correct this is to simply remove the brackets from your function:
listCustomer (Car{customers = a}) = a
Now, a simply stands for "anything in the customer field". Note that your listCustomer function is redundant, since the record syntax already provides you with a getter for the customers field:
> customers $ Car [1,2]
> [1,2]
Sum type
The Maybe Int type is a sum type.
data Maybe Int = Nothing | Just Int
From my understanding, this is due to the fact that the Nothing value constructor takes no arguments and the second value constructor called Just takes only one argument. Therefore, because no value constructor takes more than one argument, this type is a product type.
Product type
The type below is a product type since its data constructor takes two arguments and therefore is a product type.
data Colour = Person String Int
However, I am not sure how we would classify the following type in the context of the sum and product types. How should we refer to this?
data Shade = RGB Int Int Int | Transparent
All data types are "sums of products".
We sum over the number of constructors, and for each constructor we multiply over the number of arguments.
Sometimes the sum is trivial. When there is a single constructor, or none at all, we sum over a singleton or empty set. Summing over a single constructor makes the resulting type isomorphic to a product. Summing over no constructors makes the type to be empty (e.g. Data.Void.Void).
Sometimes, some of the products are trivial as well. When there is a single argument, or none at all, we multiply over a singleton or empty set. Multiplying over a single argument T simply produces T (after lifting). Multiplying over no arguments produces a type with only one value (e.g. ()).
Hence, sometimes our data is a non-trivial sum of trivial products, and we call it a "sum"; sometimes it is a trivial sum of non-trivial products, and we call it a "product". But, in the general case, it is always a "sum of products".
Note that algebraic types (up to isomorphism) form a commutative semiring, satisfying roughly the same laws of high school algebra for sums and products. In high school algebra, we can turn any expression involving nested sums and products into a polynomial, i.e. into a "sum of products". This also happens with types (up to isomorphism), hence the choice of making data types to be "sums of products" is rather expressive.
The Maybe Int type is a sum type because it has an alternation
data SumType = This | That
the fact that it has arguments on its constructors doesn't affect its "sum-ness." Sum types can also contain product constructors, such as:
type Username = String
type Email = String
-- User is a sum of three products
data User = NotLoggedIn -- nullary constructor
| Guest Username -- unary constructor
| RegisteredUser Username Email -- binary constructor
The Haskell wikibook has an example that shows how to chain lookup commands when trying to find different pieces of connected information throughout a database, seen here:
getTaxOwed :: String -- their name
-> Maybe Double -- the amount of tax they owe
getTaxOwed name =
lookup name phonebook >>=
(\number -> lookup number governmentDatabase) >>=
(\registration -> lookup registration taxDatabase)
and rewritten in do notation:
getTaxOwed name = do
number <- lookup name phonebook
registration <- lookup number governmentDatabase
lookup registration taxDatabase
Now, anytime I see a function repeated more than once I immediately try to think of ways to abstract over its repeated application, but as I haven't used Monads much in practice yet, and as they seem to already be at a pretty high level of abstraction, I didn't know how to approach that in this case.
What are some ways, if any, a coder could abstract over the common pattern above, that is, a call to lookup in every line?
(an aside: is this an appropriate context for the phrase "abstract over"? I felt it captured my meaning, but I'm not sure, and I'd like to make sure I'm using terminology appropriately as a relatively new coder; I looked through other posts which clarified its use and meaning but I still can't figure it out for this particular example)
Big thanks to Carsten for the link to foldM! Credit to them for the insight of this answer.
So, if we use foldM, we can write a function that repeatedly performs a lookup chained through multiple directories that depend upon each previous result. If, thanks to the use of monads, at any point lookup cannot find the current key in a directory, it will terminate, and return Nothing:
lookupALot :: Eq a => a -> [(a,b)] -> Maybe b
lookupALot key directories = foldM lookup key directories
this has output of the form
foldM f k1 [d1, d2, ..., dm] -- k == key, d == directory
==
do
k2 <- f k1 d1
k3 <- f k2 d2
...
f km dm
which is exactly the same structure as
do
number <- lookup name phonebook
registration <- lookup number governmentDatabase
lookup registration taxDatabase
Hence, a more compact way of writing getTaxOwed would be:
getTaxOwed :: String -> Maybe Double
getTaxOwed name = foldM lookup name [phonebook, governmentDatabase, taxDatabase]
Which kinda blows me away! That line of code will find the phone-number associated with a person's name, then check the governmentDatabase with their number for their registration, and finally find their tax information from that registration. Note though, that this will only work for data in the form of [(a,b)], as indicated by the type of lookupALot.
A problem I'm facing often when designing data type in Haskell, is to either use sum type or records of Maybe Eithers.
A simple example would be to modelize FX operation, spot or a forward, where the only difference is the presence or not of a "maturity" date ( One way would be using a sum type an explicitely specify if it's a spot or a forward.
data Amount = Amount { amount :: Double, currency :: String }
data Fx = Spot { tranDate :: Day, soldAmount :: Amount, boughtAmount :: Amount }
| Forward { tranDate :: Day, paidAmount :: Amount, boughtAmount :: Amount , maturity :: Day}
Another way would be to just have the maturity as a `Maybe'
data Fx = Fx { tranDate :: Day
, soldAmount :: Amount
, boughtAmount :: Amount
, maturity (Maybe Day)
}
Or anything else
I don't recommend working with sum types that have named fields. They are unsafe for accessors that only exist on one of the branches. And they aren't very DRY if you have repeated fields.
But instead of putting the Maybe inside of a record, I would define a wrapping record, like this:
data Spot = Spot
{ tranDate :: Day
, soldAmount :: Amount
, boughtAmount :: Amount
}
data Forward = Forward
{ spot :: Spot
, maturity :: Day
}
And perhaps even a HasSpot typeclass as well, that both Spot and Forward would implement.
But now it is difficult to put Spot and Forward values in the same collection. Perhaps one could use a type like (Maybe Day, Spot) in that case.
The "wrap it" approach of this answer doesn't generalize very well to more than one optional field, however.
The second example doesn't communicate well. You have to check maturity to distinguish forwards and spot. The sum type communicates much better.
I am attempting to create a function in Haskell returning the Resp type illustrated below in a strange mix between BNF and Haskell types.
elem ::= String | (String, String, Resp)
Resp ::= [elem]
My question is (a) how to define this type in Haskell, and (b) if there is a way of doing so without being forced to use custom constructors, e.g., Node, rather using only tuples and arrays.
You said that "the variety of keywords (data, type, newtype) has been confusing for me". Here's a quick primer on the data construction keywords in Haskell.
Data
The canonical way to create a new type is with the data keyword. A general type in Haskell is a union of product types, each of which is tagged with a constructor. For example, an Employee might be a line worker (with a name and a salary) or a manager (with a name, salary and a list of reports).
We use the String type to represent an employee's name, and the Int type to represent a salaray. A list of reports is just a list of Employees.
data Employee = Worker String Int
| Manager String Int [Employee]
Type
The type keyword is used to create type synonyms, i.e. alternate names for the same type. This is typically used to make the source more immediately understandable. For example, we could declare a type Name for employee names (which is really just a String) and Salary for salaries (which are just Ints), and Reports for a list of reports.
type Name = String
type Salary = Int
type Reports = [Employee]
data Employee = Worker Name Salary
| Manager Name Salary Reports
Newtype
The newtype keyword is similar to the type keyword, but it adds an extra dash of type safety. One problem with the previous block of code is that, although a worker is a combination of a Name and a Salary, there is nothing to stop you using any old String in the Name field (for example, an address). The compiler doesn't distinguish between Names and plain old Strings, which introduces a class of potential bugs.
With the newtype keyword we can make the compiler enforce that the only Strings that can be used in a Name field are the ones explicitly tagged as Names
newtype Name = Name String
newtype Salary = Salary Int
newtype Reports = Reports [Employee]
data Employee = Worker Name Salary
| Manager Name Salary Reports
Now if we tried to enter a String in the Name field without explicitly tagging it, we get a type error
>>> let kate = Worker (Name "Kate") (Salary 50000) -- this is ok
>>> let fred = Worker "18 Tennyson Av." (Salary 40000) -- this will fail
<interactive>:10:19:
Couldn't match expected type `Name' with actual type `[Char]'
In the first argument of `Worker', namely `"18 Tennyson Av."'
In the expression: Worker "18 Tennyson Av." (Salary 40000)
In an equation for `fred':
fred = Worker "18 Tennyson Av." (Salary 40000)
What's great about this is that because the compiler knows that a Name is really just a String, it optimizes away the extra constructor, so this is just as efficient as using a type declaration -- the extra type safety comes "for free". This requires an important restriction -- a newtype has exactly one constructor with exactly one value. Otherwise the compiler wouldn't know which constructor or value was the correct synonym!
One disadvantage of using a newtype declaration is that now a Salary is no longer just an Int, you can't directly add them together. For example
>>> let kate'sSalary = Salary 50000
>>> let fred'sSalary = Salary 40000
>>> kate'sSalary + fred'sSalary
<interactive>:14:14:
No instance for (Num Salary)
arising from a use of `+'
Possible fix: add an instance declaration for (Num Salary)
In the expression: kate'sSalary + fred'sSalary
In an equation for `it': it = kate'sSalary + fred'sSalary
The somewhat complicated error message is telling you that a Salary isn't a numeric type, so you can't add them together (or at least, you haven't told the compiler how to add them together). One option would be to define a function that gets the underlying Int from the Salary
getSalary :: Salary -> Int
getSalary (Salary sal) = sal
but in fact Haskell will write these for you if you use record syntax when declaring your newtypes
data Salary = Salary { getSalary :: Int }
Now you can write
>>> getSalary kate'sSalary + getSalary fred'sSalary
90000
Part 1:
data Elem = El String | Node String String Resp
type Resp = [Elem]
Part 2: Well... kinda. The unsatisfying answer is: You shouldn't want to because doing so is less type safe. The more direct answer is Elem needs it's own constructor but Resp is easily defined as a type synonym as above. However, I would recommend
newtype Resp = Resp { getElems :: [Elem] }
so that you can't mix up some random list of Elems with a Resp. This also gives you the function getElems so you don't have to do as much pattern matching on a single constructor. The newtype basically let's Haskell know that it should get rid of the overhead of the constructor during runtime so there's no extra indirection which is nice.