我想用外部(流)名称/值对更新记录。记录的字段有不同的类型。
我就是这样做的,有没有更优雅的 Haskell 方法来做到这一点?
data MyRec = MyRec {field1 :: String, field2 :: Int, field3 :: Bool} deriving Show
defRec = MyRec {field1 = "", field2 = 0, field3 = False}
singleUpdate :: String -> MyRec -> MyRec -> MyRec
singleUpdate "field1" urec rec = rec {field1 = field1 urec}
singleUpdate "field2" urec rec = rec {field2 = field2 urec}
singleUpdate "field3" urec rec = rec {field3 = field3 urec}
singleUpdate _ _ rec = rec
update :: [(String, MyRec)] -> MyRec -> MyRec
update flds rec = foldl (flip (uncurry singleUpdate)) rec flds
nameVals = [("field1",defRec {field1 = "foo"}), ("field3",defRec {field3 = True})]
updtdRec = update nameVals defRec
updtdRec 返回
MyRec {field1 = "foo", field2 = 0, field3 = True}
有没有更紧凑的方式,更接近这样的:
update field val = MyRec {field = val}
(这只是伪代码),适用于所有字段,而不必为每个字段指定函数实现?
最佳答案
正如 Sibi 评论的那样,你想要的是镜头。它提供了一种操作数据类型的强大方法。
例子:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data MyRec = MyRec { _field1 :: String, _field2 :: Int, _field3 :: Bool }
deriving(Show)
makeLenses ''MyRec
main :: IO ()
main = do
let myrec = MyRec { _field1 = "", _field2 = 0, _field3 = False }
myrec' = myrec & field1 .~ "updated"
myrec'' = myrec' & field2 .~ 1
myrec''' = myrec'' & field3 .~ True
print myrec -- MyRec {_field1 = "", _field2 = 0, _field3 = False}
print myrec' -- MyRec {_field1 = "updated", _field2 = 0, _field3 = False}
print myrec'' -- MyRec {_field1 = "updated", _field2 = 1, _field3 = False}
print myrec''' -- MyRec {_field1 = "updated", _field2 = 1, _field3 = True}
你可以写一个类似
update field val = MyRec {field = val}
的函数.update :: MyRec -> ASetter MyRec MyRec t t -> t -> MyRec
update record field val = record & field .~ val
> update defRec field1 "updated"
MyRec {_field1 = "updated", _field2 = 0, _field3 = False}
这些非常紧凑,但是镜头的元组和相应的值有不同的类型。例如,
(field1, "updated")
和 (field2, 1)
有不同的类型,所以很难写一个列表来更新。下面的链接将帮助您开始使用镜头。
https://hackage.haskell.org/package/lens-tutorial-1.0.0/docs/Control-Lens-Tutorial.html
关于Haskell 记录更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33470368/