Control.Lens.Setter在Haskell中使用Observable功能非常出色。 (更新数据集中的值时要触发的函数/函子。)
但是,考虑到镜头不包含在标准环境中,然后需要额外安装,没有镜头,当我只想使用原始的setter功能,如带有字段标签:
data Foo = Foo {val :: Int}
这该怎么做?
ST Monad适合这个目的吗?
谢谢。
目前还不是很清楚你在寻找什么,但如果你只是想更新一个记录字段,你可以使用Haskell记录更新语法:
x = Foo { val = 5 }
y = x { val = 42 }
这适用于任何记录,包含任意数量的字段,您不需要列出所有字段,只需列出您要更新的字段,例如:
data D = D { a :: String, b :: Int }
x = D { a = "foo", b = 42 }
y = x { a = "bar" } -- now y = D { a = "bar", b = 42 }
z = x { b = 43 } -- now z = D { a = "foo", b = 43 }
请记住,这实际上不会更新(“更改”,“改变”)内存中的值,而是创建记录的副本,其中所有字段都等于原始记录的字段,但更新的字段除外。镜头的工作方式相同,事实上Haskell中的所有内容都有,因为Haskell根本不允许变异。
我认为你在一些概念之间有点混淆;特别是,setter vs observable。
setName
(用于记录),并且用setName "foo" oldRecord
之类的东西调用它,这将保持oldRecord
原样,但返回一个名为"foo"
的新记录。如您所知,还有其他更复杂的setter实现,例如镜头。现在回答你的另一个问题:如何使用不带镜头的定位器?好吧,如果你有像data Foo = Foo {val :: Int, val2 :: String}
这样的记录(你的例子+一个额外的字段),并且你有一个旧的记录 - 让我们说oldRecord = Foo { val = 1, val2 = "test" }
,Haskell有特殊的setter语法:做oldRecord { val = 2 }
会给val
设置为2
的新记录 - 这是,它会给Foo { val = 2, val2 = "test" }
。显然,对于嵌套记录,这种语法有点笨拙,这就是镜头被发明的原因。