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

时间:2019-03-10 18:51:27

标签: haskell getter-setter setter

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

但是,考虑到镜头不包含在标准环境中,然后需要在不使用镜头的情况下进行额外安装,而我只想使用原始的设置功能(例如带有字段标签)

data Foo = Foo {val :: Int} 

该怎么做?

ST Monad是否适合此目的?

谢谢。

2 个答案:

答案 0 :(得分: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 }

请记住,这实际上并不是对内存中的值进行 update (“更改”,“变异”),而是创建具有所有内容的记录的副本除更新的字段外,其他字段均与原始记录的字段相同。镜头的工作方式相同,事实上,Haskell的所有功能都可以做到,因为Haskell根本不允许突变。

答案 1 :(得分:4)

我认为您在一些概念之间有些困惑;具体来说,是塞特犬还是可观察者。

  • 我对它们了解不多,但是正如您所描述的,可观察确实是一种每次更改值时运行函数的方法。 Haskell中不存在此概念。我敢肯定,您可以通过某种方式做到这一点,但这并不是很有用,因为(几乎)每个Haskell值都是不可变的。
  • 相反,设置器只是一个更改值一部分的函数,与Java getter和setter相同。唯一的复杂之处在于,在Haskell中,所有值都是不可变的(如上所述),因此,setter无需更改值,而是将值复制并设置了东西。例如,如果您有一个设置器setName(用于一条记录),并且使用类似setName "foo" oldRecord的名称来调用它,则将保持oldRecord不变,但会返回一个带有名称设置为"foo"。如您所知,还有其他更复杂的设置器实现,例如镜头。
  • 您还提到了 ST 。这是一个更高级的概念;它基本上是在您必须在本地使用某种可变变量但仍保留纯度(使用频率不高)时使用的。

现在要回答您的另一个问题:如何使用不带镜头的安装员?好吧,如果您有一个像data Foo = Foo {val :: Int, val2 :: String}这样的记录(您的示例+一个额外的字段),并且您有一个旧记录-假设oldRecord = Foo { val = 1, val2 = "test" },Haskell具有特殊的setter语法:做oldRecord { val = 2 }将给出一个{strong> new 记录,其中val设置为2-也就是说,它将给出Foo { val = 2, val2 = "test" }。显然,对于嵌套记录,此语法有点笨拙,这是镜头被发明的原因。