Haskell是否提供了将函数映射到数据成员的方法?

o19*_*673 12 haskell records functional-programming

我是Haskell的新手,我经常发现自己不得不用模式匹配来分解数据,只是将一个函数应用于其成员之一,然后重新组装它.

说我有:

data Car = Car { gas :: Int, licensePlate :: String }
Run Code Online (Sandbox Code Playgroud)

我希望它在开车时减半燃气,并加油,我正在做:

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 . (+)
Run Code Online (Sandbox Code Playgroud)

有没有办法在不必定义辅助函数mapGas的情况下做到这一点?因为当它由许多字段组成时,必须为每个数据成员编写一个map函数会变得相当麻烦.我知道可以为具有访问者的其中一个成员分配一个值:

runOutOfFuel:: Car -> Car
runOutOfFuel aCar = aCar { gas = 0 }
Run Code Online (Sandbox Code Playgroud)

是否可以使用访问器映射函数?如果是这样,怎么样?

Ale*_*lec 13

只使用核心库?不.但是,随着广泛使用的lens包,是的.以下是您的情况:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens.TH
import Control.Lens

data Car = Car { _gas :: Int, _licensePlate :: String }

makeLenses ''Car
Run Code Online (Sandbox Code Playgroud)

现在,您可以轻松获取/设置/修改嵌套在数据结构中的字段.

runOutOfFuel:: Car -> Car
runOutOfFuel = gas .~ 0

drive:: Car -> Car
drive = gas %~ (`div` 2)

refuel:: Int -> Car -> Car
refuel c = gas +~ c
Run Code Online (Sandbox Code Playgroud)

这里的魔力是makeLenses ''Car生成gaslicensePlate功能类似(但更强大)你的mapGas(实际上mapGas = (gas %~)).开始使用lens非常令人生畏,但我建议您只阅读示例部分.