繁体   English   中英

Haskell:使用变量创建部分自定义数据类型

[英]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

这会创建名为uidamount镜头。

您现在可以将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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM