web-dev-qa-db-ja.com

残りのフィールドをコピーしながら、レコード内の単一のフィールドを割り当てるための簡単な方法?

次のレコードADTがあるとします。

data Foo = Bar { a :: Integer, b :: String, c :: String }

次のように、1つのフィールドを除くすべてのフィールドが引数として渡されたフィールドと同じ値を持つ、レコードを取得して(同じタイプの)レコードを返す関数が必要です。

walkDuck x = Bar { a = a x, b = b x, c = lemonadeStand (a x) (b x) }

上記は機能しますが、より多くのフィールドを持つレコードの場合(たとえば10)、そのような関数を作成すると、多くのタイピングが必要になります。

同じことをするのに退屈な方法はありますか?

106
jaymmer

はい、レコードフィールドを更新する良い方法があります。 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" }
139
Chris Taylor

これは lenses の場合に適しています。

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

test = Foo 1 2 "Hello"

次に:

setL c "Goodbye" test

「test」のフィールド「c」を文字列に更新します。

31
Don Stewart

補助機能を定義したり、レンズを使用したりする必要はありません。標準のHaskellにはすでに必要なものが揃っています。ドン・スチュワートの例を見てみましょう。

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

test = Foo 1 2 "Hello"

次に、test { c = "Goodbye" }更新されたレコードを取得します。

10