Alanların geri kalanını kopyalarken bir kayıttaki tek bir alanı atamanın kısa yolu?


119

Diyelim ki aşağıdaki ADT kaydına sahibim:

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

Bir kayıt alan ve alanlardan biri hariç tümünün bağımsız değişken olarak iletilenle aynı değerlere sahip olduğu bir kayıt (aynı türden) döndüren bir işlev istiyorum, örneğin:

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

Yukarıdakiler işe yarıyor, ancak daha fazla alana sahip bir kayıt için (örneğin 10), böyle bir işlev oluşturmak, oldukça gereksiz olduğunu düşündüğüm çok sayıda yazmayı gerektirecektir.

Aynısını yapmanın daha az sıkıcı yolları var mı?


3
Güncelleme için kayıt sözdizimi mevcuttur, ancak hızla hantal hale gelir. Bunun yerine lenslere bir göz atın .
Cat Plus Plus

Yanıtlar:


155

Evet, kayıt alanlarını güncellemenin güzel bir yolu var. GHCi'de şunları yapabilirsiniz -

> 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
RecordWildCardsUzantısı kapsamında “paket açma” alanlara da güzel olabilir. Güncellemeler için pek hoş değil:incrementA x@Foo{..} = x { a = succ a }
Jon Purdy

2
BTW, Frege'de (JVM için bir Haskell) işlevi şöyle tanımlarsınız updateFoo x = x.{ c = "Goodbye" }( .operatörü not edin ).
0dB


Teşekkürler. Ne yazık ki Haskell yazmayalı uzun zaman oldu!
Chris Taylor

37

Bu lensler için iyi bir iştir :

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

test = Foo 1 2 "Hello"

Sonra:

setL c "Goodbye" test

'test'in' c 'alanını dizenize günceller.


5
Lens benzeri paketler, alanları alma ve ayarlama işlevlerine ek olarak genellikle operatörleri tanımlar. Örneğin, iirc test $ c .~ "Goodbye"nasıl lensolur? Bunun sezgisel olduğunu söylemiyorum, ancak operatörleri bir kez tanıdığınızda, o kadar kolay olmasını bekliyorum $.
Thomas M. DuBuisson

3
SetL'in nereye gittiğini biliyor musunuz ? Control.Lens'i içe aktarıyorum , ancak ghc setL'nin tanımsız olduğunu bildiriyor .
dbanas

1
setL yerine set kullanın
Subhod I

16

Yardımcı fonksiyonları tanımlamanıza veya lens kullanmanıza gerek yok. Standart Haskell'de ihtiyacınız olan şey zaten var. Don Stewart'ın örneğini ele alalım:

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

test = Foo 1 2 "Hello"

O zaman test { c = "Goodbye" }güncellenmiş bir kayıt almak için diyebilirsiniz .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.