除了Haskell中的Control.Lens.Setter之外,实现Observable的方法是什么?

问题描述 投票:-6回答:2

Control.Lens.Setter在Haskell中使用Observable功能非常出色。 (更新数据集中的值时要触发的函数/函子。)

但是,考虑到镜头不包含在标准环境中,然后需要额外安装,没有镜头,当我只想使用原始的setter功能,如带有字段标签:

data Foo = Foo {val :: Int} 

这该怎么做?

ST Monad适合这个目的吗?

谢谢。

haskell getter-setter setter
2个回答
4
投票

目前还不是很清楚你在寻找什么,但如果你只是想更新一个记录字段,你可以使用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根本不允许变异。


4
投票

我认为你在一些概念之间有点混淆;特别是,setter vs observable。

  • 我对它们知之甚少,但正如你所描述的那样,一个可观察的东西似乎是每次改变一个值时运行一个函数的方法。 Haskell中不存在这个概念;我确信你可以以某种方式实现它,但它不会非常有用,因为(几乎)每个Haskell值都是不可变的。
  • 相比之下,setter只是一个改变值的一部分的函数,与Java getter和setter相同。唯一的小问题是在Haskell中,所有值都是不可变的(如上所述),因此setter不是更改值,而是复制值,但是设置了东西。例如,如果你有一个setter setName(用于记录),并且用setName "foo" oldRecord之类的东西调用它,这将保持oldRecord原样,但返回一个名为"foo"的新记录。如您所知,还有其他更复杂的setter实现,例如镜头。
  • 你也提到ST。这是一个更先进的概念;当你必须在本地使用某种可变变量但仍保持纯度(这种情况不常见)时,它基本上被使用。

现在回答你的另一个问题:如何使用不带镜头的定位器?好吧,如果你有像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" }。显然,对于嵌套记录,这种语法有点笨拙,这就是镜头被发明的原因。

© www.soinside.com 2019 - 2024. All rights reserved.