在Haskell中编辑数据类型

时间:2018-11-04 09:51:15

标签: haskell

我需要Haskell的帮助,我有点困惑。

我有这样的自定义类型/数据:

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])

让我们假设邮件帐户存储在一个数据库中,我现在要更新联系人列表,而我不知道如何使用此签名来做到这一点:

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

我尝试过这个:

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

我创建了这三个函数:

 --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. 我的问题是,这些代码无法正常工作,因为return $ mailAccountUpdate macc x重新运行了一个列表,而不是IO MailAccount。
  2. 我还没有足够的技能来玩functorsfmap
  3. 我想要一种方法来更新我在邮件帐户中的联系人列表,这意味着我想要一种方法来访问和编辑此数据并用更新后的列表覆盖它。
  4. 我必须尊重签名,因此我尝试使用终端中的逻辑,因此我尝试了一些操作,所以我的问题是:

是否可以像OOP ex : MailAccount.contact()一样直接编辑数据?如果没有,我该如何创建一个可以完成这项工作的功能。

有没有办法让例如两个具有相同类型的mailAccount并对其进行编码,以使其在ghci终端中等效:

mail1 = mail2

这将用mail2中的数据覆盖mail1中的数据。但是我不知道如何用数据类型在haskell中进行编码。

在此先感谢大家的帮助。

2 个答案:

答案 0 :(得分:2)

有一个更整洁的版本,但是我这样做是为了使它更加理解:

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"))]

然后使用它,您将:

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

我们将Person更新为包含[Contact]的列表,因此现在联系人已附加到某人。现在每个Contact都有一个Id,我们可以用来联系正确的联系人。

您可以像updatePersonContact (Person m fn contacts)那样在输入中解构类型,因此现在我们可以使用重构人的所有位。 使用m fn,我们可以直接将它们退回,因为这些不需要更改。但是我们对contacts感兴趣,因此我们将其传递给此函数updateContact id newfullName contacts

updateContact作为输入,我们有一个IdFullName[Contact]的列表。 遍历列表的方法是使用map,因此在这里我们使用map来逐一浏览联系人列表。 map () contacts

()必须是a -> b中的函数,而我们的a第一次循环时是(1,("last1","first1"),因此您可以看到它有2个值通过拥有\(i, fn) ->来应对。 所以i == 1fn == ("last1","first1")。这些将像循环一样在列表的每次迭代中更新。

接下来的部分我们检查是否为i == id,如果是,则为我们要更新的联系人,因此我们返回(i, newfullName),这是我们最初传递给updatePersonContact的新全名。如果iid不匹配,那么我们就不理会这些值,并在它们出现时返回它们。

map是一个函子,因此您可能会发现它还不错,您可能需要对其进行更多阅读才能获得更好的理解。 :)

在Haskell中,列表是不可变的,这意味着每次给您一个列表时,您都必须返回一个全新的列表。

答案 1 :(得分:2)

检查您的联系人功能。应该是

contacts (_,x) = x 

MailAccount是一个元组,第一个元素是person,第二个元素是contact。因此它不能是(,x),而应该是(_,x)。

下面的updatecontact定义工作正常。

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

我与其他人一样,不需要在定义上使用IO。没有IO,该错误将很容易理解。