简体   繁体   中英

Editing data type in Haskell

i need help with haskell i'm kinda confused.

I have custom types/Data like this:

type Name         = String 
type LastName     = String
type Mail         = String
type FullName     = (LastName, Name)

data Person       = Person Mail FullName deriving (Show, Read)
type Contact      = (FullName,Mail)
type MailAccount = (Person,[Contact])

Let's assume that mail account is stored in a data_base , what i want from now is update the list of contact and i don't know how to do it using this signature:

updateContact :: Mail -> LastName -> Name ->MailAccount -> IO MailAccount

I tried with this :

updateContact l n m macc = do
           x <- createPerson l n m
           return $ mailAccountUpdate macc x

I created these three function:

 --return my list of contacts
  contacts:: MailAccount->[Contact]
  contacts (_,_,con) = con

  createPerson l n m = do
       return (Person m (l,n))

  mailAccountUpdate acc x = do 
       return (x:contact acc)
  1. My problem is that thes code won't work because return $ mailAccountUpdate macc x retruns a list and not an IO MailAccount.
  2. I'm not skilled enough to play with the functors and fmap yet.
  3. I want a way to update my list of contact in the mail account , meaning i want a way to access and edit this data and override it with the updated list.
  4. I have to respect the signature , so i tried to play with the logic in the terminal, so i tried a few things so my question is :

Is there a way to edit the data directly like OOP ex : MailAccount.contact() ? if not how can i create a function that can do the work.

Is there a way to have for example two mailAccount with the same type and code it to do the equivalent of this in the ghci terminal :

mail1 = mail2

This will override the data in mail1 with the data from mail2. but i dont know how to code it in haskell with data type.

Thank you everyone in advance for helping me.

There is a neater version of this but I'm doing like this so it can be more understanding:

type Name     = String
type LastName = String
type Mail     = String
type Id       = Int
type FullName = (LastName, Name)
type Contact  = (Id, FullName)

data Person =
  Person Mail FullName [Contact]
  deriving (Show, Read)

updatePersonContact :: Person -> FullName -> Id -> Person
updatePersonContact (Person m fn contacts) newfullName id =
    Person m fn (updateContact id newfullName contacts)

updateContact :: Id -> FullName -> [Contact] -> [Contact]
updateContact id newfullName contacts =
  map (\(i, fn) ->
         if i == id
         then (i, newfullName)
         else (i, fn)) contacts

person1 :: Person
person1 = Person "email@me.com"("last","first")
            [(1,("last1","first1")), (2,("last2","first2"))]

then using it you would:

> updatePersonContact person1 ("NEW","NEWW") 2
-- Person "email@me.com" ("last","first") [(1,("last1","first1")),(2,("NEW","NEWW"))]

We've update Person to have a list of [Contact] so now contacts are attached to a person. Each Contact now has an Id that we can use for getting to the right contact.

You can deconstruct your types in the input like so updatePersonContact (Person m fn contacts) so now we can use all the bits we need to reconstruct our person. With m fn we give them straight back as those don't need changing. But we're interested in contacts so we pass it to this function updateContact id newfullName contacts .

In updateContact as inputs we have an Id , FullName and list of [Contact] . the way to loop over a list is to use map so here we are using map to go through our list of contacts one by one. map () contacts

the () needs to be a function from a -> b and our a when it loops the first time is (1,("last1","first1") so as you can see it has 2 values which we deal with by having \\(i, fn) -> . So i == 1 and fn == ("last1","first1") . These would update on every iteration of the list like any loop.

The next part we check if i == id and if it does then that's the contact we want to update so we return (i, newfullName) which is our new full name originally passed into updatePersonContact . If i doesn't match id then let's just leave those values alone and return them as they came.

map is a functor so as you might see it's not that bad you might need to do a bit more reading on it to get a better understanding. :)

In Haskell lists are immutable which means every time you are given a list you must return a brand new list.

Check you contacts function. It should be

contacts (_,x) = x 

MailAccount is a tuple, with first element as person and second as contact. So it cannot be ( , ,x) but should be (_,x).

The below updatecontact definition is working fine.

updateContact l n m macc = let myP = Person l (n,m) 
                               newMacc = (myP,((n,m),l):contacts macc) 
                           in return newMacc

I agree with others that there is no need for using IO in definition. The error would have been understood easily without IO.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM