从Haskell中该类的给定值获取数据类

时间:2016-03-21 16:24:32

标签: haskell

我有两个定义

data Person = Person Name Surname [Projects]
data Employees = Employees [Person] Salary

我希望通过使用员工中的人员列表来获取给定姓名的相应人员,并在相应的人员中进行一些更改。例如,我想将项目添加到我想要执行项目的人员的项目列表中。我怎么能在Haskell中做到这一点?

函数签名应该像

myfunction :: Employees -> Name -> Employees

1 个答案:

答案 0 :(得分:1)

我们可以通过模式匹配和使用ext_modules直接写出来。

在这种情况下,我们可以从编写一个小帮助函数开始,对单个map值执行本地修改,并使用Person之类的东西将我们的转换应用于一大堆其他数据。所以我们可能有

map

然后我们可以编写更多代码来将此转换统一应用于我们的 updatePerson :: Name -> Person -> Person updatePerson targetName (Person name sur projects) | targetName == name = Person name sur (NewProject : project) | otherwise = Person name sur projects 数据

Employee

在您的方案中,这是正确的做法。但是,我们可能会大量访问这些数据结构的一部分,因此对它进行一些优化是有意义的!通过编写一些辅助函数来操作我们的数据类型,我们可以看到如何获得更通用的方法:

myFunction :: Person -> Person
myFunction name (Employee ps salary) = 
  Employee (map (updatePerson name) ps) salaray

然后写一些类似

的内容
personName :: Person -> Name
personName (Person name sur projects) = name

modifyProjects :: ([Project] -> [Project]) -> Person -> Person
modifyProjects f (Person name sur p) = Person name sur (f p)

现在我用辅助函数而不是直接模式匹配来编写它,因为它建议我们使用Haskell的内置功能来生成这些函数,记录。

 myFunction name (Employee people salary) = Employee (map go people) salary
   where go p | personName p == name = modifyProject ... p
              | otherwise = p

然后我们可以做类似

的事情
data Person = Person { _name :: Name
                     , _surname :: Surname
                     , _projects :: [Projects]
data Employees = Employees {_people :: [Person], _salary :: Salary}

但现在这仍然很笨重,Haskell的记录系统有点难以使用。这实际上是许多疯狂强大的库实现“镜头”的推动力,它使我们能够使用一套通用组合器实现这些记录,如转换。我提供相应的镜头代码作为Haskell扩展的一个例子来做一些很酷的事情,但我上面提到的3个替代方案中的任何一个都非常精细且复杂得多

myFunction name e = e {_people = map go (_people e}}
  where go p | _name p == name = p {_projects = New :: _projects p}
             | otherwise = p