在复制其余字段时,在记录中分配单个字段的简便方法?

jay*_*ica 109 haskell record

假设我有以下记录ADT:

data Foo = Bar { a :: Integer, b :: String, c :: String }
Run Code Online (Sandbox Code Playgroud)

我想要一个记录并返回记录(相同类型)的函数,其中除了一个字段之外的所有字段都具有与作为参数传递的值相同的值,如下所示:

walkDuck x = Bar { a = a x, b = b x, c = lemonadeStand (a x) (b x) }
Run Code Online (Sandbox Code Playgroud)

上面的工作,但对于具有更多字段的记录(比如说10),创建这样的函数将需要大量的打字,我觉得这是非常不必要的.

是否有任何不那么繁琐的方式做同样的事情?

Chr*_*lor 141

是的,这是一种更新记录字段的好方法.在GHCi你可以做 -

> data Foo = Foo { a :: Int, b :: Int, c :: String }  -- define a Foo
> let foo = Foo { a = 1, b = 2, c = "Hello" }         -- create a Foo
> let updateFoo x = x { c = "Goodbye" }               -- function to update Foos
> updateFoo foo                                       -- update the Foo
Foo {a = 1, b = 2, c = "Goodbye" }
Run Code Online (Sandbox Code Playgroud)

  • `RecordWildCards`扩展也可以很好,以"解包"范围内的字段.对于更新,它不是那么好:`incrementA x @Foo {..} = x {a = succ a}` (6认同)
  • 顺便说一句,在Frege(一个用于JVM的Haskell)中,你将函数定义为```updateFoo x = x.{c ="Goodbye"}```(注意```.```运算符). (2认同)

Don*_*art 33

这是一个很好的镜头工作:

data Foo = Foo { a :: Int, b :: Int , c :: String }

test = Foo 1 2 "Hello"
Run Code Online (Sandbox Code Playgroud)

然后:

setL c "Goodbye" test
Run Code Online (Sandbox Code Playgroud)

会将'test'的字段'c'更新为您的字符串.

  • 除了获取和设置字段的功能之外,类似镜头的包通常定义操作符.例如,`test $ c .~"Goodbye"`是`lens`会怎么做的iirc.我不是说这是有说服力的,但是一旦你了解了操作符,我就会发现它会像`$`一样容易. (4认同)
  • 你知道_setL_去了哪里?我正在导入_Control.Lens_,但ghc报告_setL_未定义. (3认同)

Wol*_*sch 12

您无需定义辅助功能或使用镜头.标准Haskell已经满足您的需求.让我们以Don Stewart为例:

data Foo = Foo { a :: Int, b :: Int , c :: String }

test = Foo 1 2 "Hello"
Run Code Online (Sandbox Code Playgroud)

然后你可以说test { c = "Goodbye" }要获得更新的记录.