Cara singkat untuk menetapkan satu bidang dalam catatan, sambil menyalin bidang lainnya?


119

Katakanlah saya memiliki catatan ADT berikut:

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

Saya ingin fungsi yang mengambil record dan mengembalikan record (dengan tipe yang sama) di mana semua kecuali satu bidang memiliki nilai yang identik dengan yang diteruskan sebagai argumen, seperti:

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

Cara di atas berfungsi, tetapi untuk rekaman dengan lebih banyak bidang (katakanlah 10), membuat fungsi seperti itu akan memerlukan banyak pengetikan yang menurut saya tidak terlalu diperlukan.

Apakah ada cara yang tidak terlalu membosankan untuk melakukan hal yang sama?


3
Rekam sintaks untuk memperbarui ada, tetapi dengan cepat menjadi rumit. Lihatlah lensa sebagai gantinya.
Cat Plus Plus

Jawaban:


155

Ya, ada cara yang bagus untuk memperbarui bidang rekaman. Di GHCi Anda dapat melakukan -

> 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" }

9
The RecordWildCardsekstensi bisa bagus juga, untuk “membongkar” bidang dalam lingkup. Untuk pembaruan, itu tidak terlalu bagus:incrementA x@Foo{..} = x { a = succ a }
Jon Purdy

2
BTW, di Frege (Haskell untuk JVM) Anda akan mendefinisikan fungsi sebagai updateFoo x = x.{ c = "Goodbye" }(perhatikan .operatornya).
0dB


Terima kasih. Sayangnya sudah lama sekali saya tidak menulis Haskell!
Chris Taylor

37

Ini adalah pekerjaan yang bagus untuk lensa :

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

test = Foo 1 2 "Hello"

Kemudian:

setL c "Goodbye" test

akan memperbarui bidang 'c' dari 'test' ke string Anda.


5
Dan paket seperti lensa sering kali menentukan operator selain fungsi untuk mendapatkan dan menyetel bidang. Misalnya, test $ c .~ "Goodbye"adalah bagaimana lensmelakukannya iirc. Saya tidak mengatakan ini intutitif, tetapi begitu Anda mengetahui operatornya maka saya berharap itu akan datang semudah $.
Thomas M. DuBuisson

3
Apakah Anda tahu kemana perginya setL ? Saya mengimpor Control.Lens , tetapi ghc melaporkan bahwa setL tidak ditentukan.
dbanas

1
gunakan set sebagai ganti setL
Subhod I

16

Anda tidak perlu menentukan fungsi tambahan atau menggunakan lensa. Standar Haskell sudah memiliki apa yang Anda butuhkan. Mari kita ambil contoh oleh Don Stewart:

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

test = Foo 1 2 "Hello"

Kemudian Anda bisa mengatakan test { c = "Goodbye" }untuk mendapatkan catatan yang diperbarui.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.