Haskell中实现mapEmployee函数修改Employee属性的技术问询
我正在完成一个编程练习,现有一个类型为Employee的员工列表,定义如下:
data Employee = Employee Name Age Salary deriving (Show) employees :: [Employee] employees = [ Employee "Alice" 28 50000.0, Employee "Bob" 35 60000.0, Employee "Charlie" 42 75000.0, Employee "David" 30 55000.0, Employee "Eva" 25 48000.0 ]
需要实现函数mapEmployee :: (Name -> Name) -> (Age -> Age) -> (Salary -> Salary) -> Employee -> Employee,形式为mapEmployee n a s e = (function),用于替换给定Employee条目的姓名、年龄和薪资。
题目要求使用3个函数,我认为需要编写3个辅助函数来实现mapEmployee。此前我已定义了getName、getAge和getSalary函数,格式如下:
getName :: Employee -> Name getName (Employee n _ _) = n
但由于对函数式编程理解不足,我不清楚如何在此场景中使用这些getter函数。我曾考虑用filter函数查找索引并替换整个Employee条目,但目前既无法成功筛选索引,也不知道替换属性的方法。
首先明确:mapEmployee的输入是单个Employee实例,不需要用filter或索引操作,直接针对实例的三个字段做转换即可。你的getName这类getter是用来提取字段值的,我们要做的是用传入的转换函数处理原字段值,再生成新的Employee实例。
1. 编写三个字段转换辅助函数
按照题目要求的3个函数,我们可以写三个分别负责修改姓名、年龄、薪资的辅助函数:
-- 修改姓名:接收姓名转换函数和Employee,返回新实例 mapName :: (Name -> Name) -> Employee -> Employee mapName f e = Employee (f (getName e)) (getAge e) (getSalary e) -- 修改年龄:接收年龄转换函数和Employee,返回新实例 mapAge :: (Age -> Age) -> Employee -> Employee mapAge f e = Employee (getName e) (f (getAge e)) (getSalary e) -- 修改薪资:接收薪资转换函数和Employee,返回新实例 mapSalary :: (Salary -> Salary) -> Employee -> Employee mapSalary f e = Employee (getName e) (getAge e) (f (getSalary e))
2. 组合辅助函数实现mapEmployee
将三个辅助函数按顺序组合,依次对Employee的三个字段应用转换:
mapEmployee :: (Name -> Name) -> (Age -> Age) -> (Salary -> Salary) -> Employee -> Employee mapEmployee n a s e = mapSalary s (mapAge a (mapName n e))
也可以用函数组合运算符.简化写法:
mapEmployee n a s = mapSalary s . mapAge a . mapName n
补充:更直接的实现方式
如果不想拆分辅助函数,也可以直接通过模式匹配提取原字段,结合转换函数生成新实例:
mapEmployee n a s (Employee oldName oldAge oldSalary) = Employee (n oldName) (a oldAge) (s oldSalary)
不过这种写法没有用到三个独立函数,不符合题目要求,所以优先选择拆分辅助函数的方案。
为什么不用filter?
filter的作用是从列表中筛选符合条件的元素,而mapEmployee是处理单个Employee实例的函数,和列表筛选无关。如果后续需要修改列表中的某个特定Employee,才需要结合查找逻辑,但当前需求不需要这一步。
内容的提问来源于stack exchange,提问作者Armin Haas

