haskell - 在 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)
- 我的问题是这些代码不起作用,因为 return 重新
$ mailAccountUpdate macc x
运行一个列表而不是一个 IO MailAccount。 - 我还不够熟练,无法玩 the
functors
andfmap
。 - 我想要一种方法来更新我的邮件帐户中的联系人列表,这意味着我想要一种访问和编辑这些数据并用更新的列表覆盖它的方法。
- 我必须尊重签名,所以我尝试使用终端中的逻辑,所以我尝试了一些事情,所以我的问题是:
有没有办法像 OOP 一样直接编辑数据ex : MailAccount.contact()
?如果不是,我如何创建一个可以完成工作的函数。
有没有办法让例如两个具有相同类型的 mailAccount 并对其进行编码以在 ghci 终端中执行等效操作:
mail1 = mail2
这将使用 mail2 中的数据覆盖 mail1 中的数据。但我不知道如何在 haskell 中使用数据类型对其进行编码。
提前感谢大家帮助我。
解决方案
有一个更简洁的版本,但我这样做是为了更容易理解:
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
输入,我们有一个Id
,FullName
和 的列表[Contact]
。遍历列表的方法是使用map
,所以这里我们使用 map 来一一浏览我们的联系人列表。map () contacts
()
需要成为一个函数,并且a -> b
我们a
第一次循环的时候是(1,("last1","first1")
这样,你可以看到它有 2 个值,我们通过 have 来处理\(i, fn) ->
。所以i == 1
和fn == ("last1","first1")
。这些将像任何循环一样在列表的每次迭代中更新。
下一部分我们检查是否i == id
以及如果它是我们想要更新的联系人,所以我们返回(i, newfullName)
这是我们最初传入的新全名updatePersonContact
。如果i
不匹配id
,那么让我们不理会这些值并在它们到来时返回它们。
map
是一个仿函数,因此您可能会看到它并没有那么糟糕,您可能需要对它进行更多阅读才能更好地理解。:)
在 Haskell 中,列表是不可变的,这意味着每次给您一个列表时,您都必须返回一个全新的列表。
推荐阅读
- android - 如何通过 REST API 将 APK/Bundle 上传到 Firebase 测试实验室?
- terraform - 如何为不是为 terraform 中的每个模块创建资源?
- c# - 如何使控件失去焦点单击它之外的任何位置?
- sql - SQLite 在递归 CTE 上是否存在性能不足或者我写错了 sql?
- swift - 使用 ToolbarItem(placement: .principal) re: largeTitle 的正确方法是什么?
- java - 传递给 @OneToMany 和 @OneToOne 的 Spring Boot Data JPA 分离实体
- sql-server - 如何在将源的最大日期添加到其他源的同时对不同的源求和
- typescript - const 变量作为类型 - 打字稿
- prometheus - 获取每个时间序列的最新值
- reactjs - 是否可以使用对象类型定义来构造新的数组/元组类型?