【发布时间】:2017-04-05 20:42:54
【问题描述】:
我是一名 Haskell 菜鸟,我经常发现自己必须使用模式匹配分解数据,才能将函数应用于其中一个成员,然后重新组装它。
说我有:
data Car = Car { gas :: Int, licensePlate :: String }
我希望它在行驶时将油量减半并加油,我正在这样做:
mapGas:: (Int -> Int) -> Car -> Car
mapGas f (Car aGas aLicensePlate) = Car (f aGas) aLicensePlate
drive:: Car -> Car
drive = mapGas (flip div 2)
refuel:: Int -> Car -> Car
refuel = mapGas . (+)
有没有办法做到这一点而不必定义辅助函数 mapGas?因为当数据由许多字段组成时,必须为数据的每个成员编写一个映射函数会变得相当麻烦。我知道可以为具有访问器的成员之一赋值:
runOutOfFuel:: Car -> Car
runOutOfFuel aCar = aCar { gas = 0 }
是否也可以使用访问器映射函数?如果有,怎么做?
【问题讨论】:
-
我觉得你应该看看
lens的一些教程hackage.haskell.org/package/lens -
只是为了记录,没有镜头,我认为你能做的最好的是
mapGas f = (\car -> car {gas = f (gas car)})。这至少避免提及其他领域。 -
@chi 在这些情况下我通常会尝试保持对称性:
mapGas f = (\car@Car{ gas = g } -> car {gas = f g })。更长,但可以看到->两侧的gas字段。
标签: haskell functional-programming records