[英]Haskell: Creating Partial of Custom Data Type With Variables
我有一个工作函数,它使用警卫来确定如何创建自定义数据类型(在本例中为Transaction
)的副本,但在这样做时只更改一个字段。 解决这个问题的惯用方法是什么?
如果我可以在我的部分中使用变量作为键,我可以将函数简化为如下所示:
change n val uid list = do
let partial x = x {uid = uid, n = val}
mergeData partial uid list
但我似乎找不到一种方法来使用变量作为键或调用所有守卫通用的函数。
change :: [Char] -> [Char] -> String -> [Transaction] -> IO ()
change n val uid list
| n == "amount" = do
let partial x = x {uid = (id uid), amount = (id val)}
mergeData partial uid list
| n == "user" = do
let partial x = x {uid = (id uid), user = (id val)}
mergeData partial uid list
| n == "category" = do
let partial x = x {uid = (id uid), user = (id val)}
mergeData partial uid list
| n == "description" = do
let partial x = x {uid = (id uid), description = (id val)}
mergeData partial uid list
PS mergeData
是另一个函数,它使用编辑过的字段创建这个复制的Transaction
实例。
你可以用镜头吗?
你需要
{-# LANGUAGE TemplateHaskell #-}
和
import Control.Lens (makeLenses, (.~))
在您的模块文件中。
然后,猜测Transaction
样子,你可以这样定义它:
data Transaction = Transaction {
_uid :: String
, _amount :: String
, _user :: String
, _description :: String }
deriving (Show, Eq)
makeLenses ''Transaction
这会创建名为uid
、 amount
镜头。
您现在可以将change
功能简化为:
change' :: (Transaction -> Transaction) -> String -> [Transaction] -> IO ()
change' l uidValue = mergeData ((uid .~ uidValue) . l) uidValue
为了测试,我首先像这样定义了mergeData
,因为它似乎适合 OP change
函数中使用的类型:
mergeData :: (Transaction -> Transaction) -> String -> [Transaction] -> IO ()
mergeData f _ = mapM_ (print . f)
这里有些例子:
λ> ts = [Transaction "1" "42" "Joan" "Foo", Transaction "2" "1337" "Nigel" "Bar"]
λ> change' (amount .~ "0") "7" ts
Transaction {_uid = "7", _amount = "0", _user = "Joan", _description = "Foo"}
Transaction {_uid = "7", _amount = "0", _user = "Nigel", _description = "Bar"}
λ> change' (user .~ "Jane") "7" ts
Transaction {_uid = "7", _amount = "42", _user = "Jane", _description = "Foo"}
Transaction {_uid = "7", _amount = "1337", _user = "Jane", _description = "Bar"}
如您所见, amount .~ "0"
将所有_amount
标签设置为"0"
,而user .~ "Jane"
将所有_user
标签设置为"Jane"
。 两个表达式都具有类型Transaction -> Transaction
:
λ> :type amount .~ "0"
amount .~ "0" :: Transaction -> Transaction
λ> :type user .~ "Jane"
user .~ "Jane" :: Transaction -> Transaction
如果您不喜欢唱片标签中的下划线,您可以使用makeLensesFor
而不是makeLenses
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.