I have created the type Contact, and I'm trying to create a function that takes 4 parameters (First Name, Last Name, Phone and State) and creates a contact and adds it to a list of existing contact.
type LastName = String
type FirstName = String
type Phone = String
type Contact = (Person, State)
data Person = Person Phone Name deriving (Show, Read)
type Name = (FirstName, LastName)
data State = Good | Bad
addContact :: Phone -> FirstName -> LastName -> State -> [Contact] -> [Contact]
addContact c p n s [] = Contact (Person c (p,n) ,s) : []
addContact c p n xs = Contact (Person c (p,n) , s) : xs
I can't seems to find a solution on LYAH or SOF, I'm following exactly what this section says, particularly the section about shape: http://learnyouahaskell.com/making-our-own-types-and-typeclasses#record-syntax but I'm getting the following compilation error:
• Data constructor not in scope:
Contact :: (Person, [Char]) -> Contact
I tried to change the upper case for lowercase for the type and I still got undefined variable error compilation.
Is there something I'm missing here?
Contact is not the type constructor, Contact is just an alias for (Person, State), so a 2-tuple, hence (,) is the data constructor:
addContact :: Phone -> FirstName -> LastName -> State -> [Contact] -> [Contact]
addContact c p n s xs = (,) (Person c (p,n)) s : xs
or less verbose:
addContact :: Phone -> FirstName -> LastName -> State -> [Contact] -> [Contact]
addContact c p n s xs = (Person c (p,n), s) : xs
You data type for Person is not valid, it should either be:
data Person = Person Phone Name deriving (Show, Read)
or you can work with a type alias, for example:
type Person = (Phone, Name)
then you thus implement this with:
addContact :: Phone -> FirstName -> LastName -> State -> [Contact] -> [Contact]
addContact c p n s xs = ((Person c (p, n)), s) : xs
or:
addContact :: Phone -> FirstName -> LastName -> State -> [Contact] -> [Contact]
addContact c p n s xs = ((c, (p, n)),s) : xs
finally the name type again has a problem, you can not write spaces between First and Name, and you should use parenthesis:
type Name = (FirstName, LastName)
Related
I'm trying to implement a function that adds an element (a type) to a list of this type to an existing created datatype. Since Haskell data variable are immutable, I know that you have to create a new data with the same characteristic as the first one and add onto it, but I can seem to make ghci compile my program and make it do what I'm trying to accomplish.
Here is my code and the function which should add a contact to a list of already existing contact addContact which I'm been trying to work on:
type Model = String
type Serie = String
type SerialNumber = String
type Type= (Model, Serie)
data Car = Car
SerialNumber
Type
deriving (Show, Read)
type PastCars= (Car, ChangeCause)
data ChangeCause = Broken | Contract deriving (Show, Eq, Read)
type Phone = (Extension, Number)
type Number = String
type Extension = String
type Person = (FirstName, LastName)
type FirstName = String
type LastName = String
type Contact = (Person, Phone)
data Owner = Owner Car Phone [PastCars] [Contact]
--Getters
listPastSN [] = []
listPastSN ((p,e):xs) = (serialNumber p, e):listPastSN xs
serialNumber :: Car -> String
serialNumber (Car s _)= s
car :: Owner -> Car
car (Owner c _ _ _ ) = c
phone :: Owner -> Phone
phone (Owner _ p _ _ ) = p
pastCar :: Owner -> [PastCars]
pastCar (Owner _ _ p _ ) = p
contacts :: Owner -> [Contact]
contacts (Owner _ _ _ c) = c
addContact :: FirstName -> LastName -> Extension -> Number -> Owner -> Owner
addContact f l e n ow = Owner car(ow) phone(ow) pastCar(ow) contacts(ow) ++ (Contact ((f, l), (e, n)))
Let's I have these data variable
car1 = Car "X234X" ("Honda", "Civic")
car2 = Car "X233X" ("Mazda", "3")
person1 = Person "Peter" "Mcleod"
owner1 = Owner car1 ("888" , "4144144") [(car2, Broken)] [(person1,("123", "1231231")) ]
I want to be able to add another contact to the list of contact of owner1.
What is the correct way to go about this. SO and LYAH solution proposed around these type of case don't seem to help.
There are multiple issues in your code. The fixed version of the addContact function:
addContact f l e n ow =
Owner (car ow) (phone ow) (pastCar ow) $ (contacts ow) ++ [((f, l), (e, n))]
Contact is not a constructor, it's a type alias.
f a(b) is the same as f a b. So Owner phone(x) is the same Owner phone x, the same applies to the other arguments.
Take a look at the signature of (++) :: [a] -> [a] -> [a]. You are trying, contacts(ow) ++ (Contact ((f, l), (e, n)).
f a b ++ [1,2,3] is the same as (f a b) ++ [1,2,3]. What you wanted is f a (b ++ [1,2,3]) or f a $ b ++ [1,2,3].
I'm trying to make a haskell program with modules and create my own types to simulate a election: So far I have this:
module Election
( nactionCreate
, getState
, addVotesToState
, nactionAddVotes
, stateWinner
, electionWinner
) where
-- Types Created
data Candidate = A | B deriving (Eq, Show)
type State = (String, Int, Int, Int) --deriving (Eq, Show, Read)
name :: State -> String
name (name, _, _, _) = name
representativesNumber :: state -> Int
representativesNumber (_, representativesNumber, _, _,) = representativesNumber
aVotes :: State -> Int
aVotes (_, _, aVotes, _) = aVotes
bVotes :: State -> Int
bVotes (_, _, _, bVotes) = bVotes
type Naction = [State]
-- Create a Naction From a tuples List for each State at the beginning of Election. In the beginnig each candidate has 0 votes
nactionCreate:: [(String,Int)] -> Naction
nactionCreate ((n,r):xs) = [State | name <- n, representativeNumber<-r, 0, 0]
-- Return the State with the name equal to the String. Don't exists states with equals name
getState :: Naction -> String -> State
getState [] _ = null
getState ((n,_,_,_):xs) s =
| n == s = State
| otherwise = getState xs s
-- TODO
addVotesToState :: State -> Int -> Int -> State
-- TODO
nactionAddVotes :: Naction -> [(String, Int, Int)] -> Naction
-- TODO
stateWinner :: State -> Candidate
-- TODO
electionWinner :: Naction -> Candidate
but i'm having a hard time knowing how to manipulate mas data/types. Like for example in nactionCreate it's suppose to work like:
> naction0 =createNaction [("North",4), ("Central",6), ("West",3)]
and then I should could be able to do:
> north0 = getState naction0 "North"
> representativesNumber north0
4
> aVotes north0
0
> bVotes north0
0
I know that the function that I already made aren't correct (I mean I suspect) but I can't understand why or how to work with... Can someone help me please?
P.S.: I dont wanna help with the functions I haven't tried to make yet.
Your getState isn't actually creating a value of type State; you are just using the type constructor in a place where is cannot be used. You are getting an error because there is no data constructor named State. You want to return the value that had the name n instead.
There's also no such value as null. You want the return type to be Maybe State, using Nothing to signal failure and Just to wrap a successful match.
getState :: Naction -> String -> Maybe State
getState [] _ = Nothing
getState (state#(n,_,_,_):xs) s =
| n == s = Just state
| otherwise = getState xs s
Here the name state refers to the head of the list of State values as a whole, so that you don't have to capture and repeat all the values in the tuple.
I have five different types:
type Name = string
type PhoneNumber = int
type Sex = string
type YearOfBirth = int
type Interests = string list
type Client = Name * PhoneNumber * Sex * YearOfBirth * Interests
Which represent clients. Then let's say I have three of these clients:
let client1 = "Jon", 37514986, "Male", 1980, ["Cars"; "Sexdolls"; "Airplanes"]
let client2 = "Jonna", 31852654, "Female", 1990, ["Makeup"; "Sewing"; "Netflix"]
let client3 = "Jenna", 33658912, "Female", 1970, ["Robe Swinging"; "Llamas"; "Music"]
let clients = [client1; client2; client3]
How would I go about searching through clients for a certain element? Say, I have a method where I want to get the names of the clients with the same sex as me? I've written the below function for at least determining whether the input sex is the same but that doesn't cut it apparently.
let rec sexCheck sex cs =
match cs with
| [] -> []
| c::cs -> if sex = c then sex else sexCheck sex cs
sexCheck "Male" clients
Any hints?
You can accumulate the results in another parameter, like this:
let sexCheck sex cs =
let rec loop acc (sex:string) cs =
match cs with
| [] -> acc
| ((_, _, s, _, _) as c)::cs -> loop (if sex = s then c::acc else acc) sex cs
loop [] sex cs
As usual, I would like to remind you what's the easiest way, by using the provided functions in F#:
clients |> List.filter (fun (_, _, c, _, _) -> c = "Male")
So I have a custom data type Person
data Person = Person{ fname :: String
, lname :: String
, age :: Int
, siblings :: [String]
}
I have a list of this type, foo = [Person].
I'm trying to update a particular Person. My process is to match their fname (Assuming each name is unique) and then to update their siblings values.
addSiblingToPerson :: String -> String -> [Person] -> [Person]
addSiblingToPerson siblingParam fnameParam fooParam =
I'm really struggling to think 'functionally', if I were to do this in an imperative language I could go through each item in [Person] checking to see if name == fname then this.siblings push newSibling (Or something along those lines)
I know how to update a record in haskell but I want to return the list of Person after updating a single person in the collection of Person.
I just can't wrap my head around how to 'think Haskell'
Thank you :(
You shouldn't think about "updating" something, even though we use that terminology, unless you have a mutable reference and are working in the IO monad. In this situation the thought process should be "how do I compute a new list that is exactly like the previous one except...".
You could either update a single entry or map a modification function across the entire list. Lets look at the manual, single entry, solution first:
addSiblingToPerson :: String -> String -> [Person] -> [Person]
addSiblingToPerson siblingParam fnameParam allPeople =
case allPeople of
[] -> []
(p:ps) | fname p == fnameParam ->
p { siblings = siblingParam : siblings p } : ps
| otherwise ->
p : addSiblingToPerson siblingParam fnameParam ps
That is, we traverse the list, keeping any non-matching people and updating the first person with a matching fname, being sure to include the rest of the list.
The map solution is functionally different - it will update all people who share the given fname and it will traverse the whole list.
addSiblingToPerson :: String -> String -> [Person] -> [Person]
addSiblingToPerson siblingParam fnameParam allPeople =
let update p | fname p == fnameParam = p { siblings = siblingParam : siblings p }
| otherwise = p
in map update allPeople
I implemented following code to make a new entry in a list of persons (including name and birth date). The List is sorted by the alphabet and should maintain this sorting. If a name is the same, the date defines the sorting. The function dateTurn turns the date around and works perfectly fine.
type Lastname = String
type Firstname = String
dateTurn :: (Int, Int, Int) -> (Int, Int, Int)
dateTurn (a,b,c) = (c,b,a)
new :: ((Lastname,Firstname),(Int,Int,Int)) -> [((Lastname,Firstname),(Int,Int,Int))] -> [((Lastname,Firstname),(Int,Int,Int))]
new x [] = [x]
new x (y:ys)
|(fst x)<(fst y) = x:(y:ys)
|(fst x)>(fst y) = y: (new x ys)
|(fst x)==(fst y) = if (dateTurn (snd x))<(dateTurn (snd y)) then y: (new x ys) else (x:y:ys)
There is no error compiling the script. If I add a person tupel to an empty list it works. However, if I add to an non-empty list. The program doesn't stop working, I have to interrupt it to stop working. So, how can this be solved?
Since your operation is generic you should abstract it
insertSorted :: Ord a => a -> [a] -> [a]
insertSorted x [] = [x]
insertSorted x (y:ys) | x <= y = x: y: ys
| otherwise = y: insertSorted x ys
then, instance your types to Ord
data Person = Person { name :: String
, age :: Int
} deriving (Eq, Show)
instance Ord Person where
(Person a _) `compare` (Person b _) = a `compare` b
then
print $ insertSorted (Person "Peter" 5) [ Person "John" 6
, Person "Zorn" 3]