2013-02-19 18 views
88

Hãy nói rằng tôi có ADT kỷ lục sau đây:Cách viết tắt để gán một trường đơn lẻ trong một bản ghi, trong khi sao chép phần còn lại của các trường?

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

Tôi muốn có một chức năng mà phải mất một kỷ lục và trả về một kỷ lục (cùng loại), nơi tất cả nhưng một trong những lĩnh vực có giá trị giống với một trôi qua như là đối số, như vậy:

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

các công trình trên, nhưng đối với một kỷ lục với nhiều lĩnh vực (nói 10), tạo ra một chức năng như vậy sẽ đòi hỏi rất nhiều cách gõ mà tôi cảm thấy là khá cần thiết.

Có cách nào ít tẻ nhạt hơn để làm giống nhau không?

+2

Ghi lại cú pháp để cập nhật, nhưng nhanh chóng trở nên cồng kềnh. Hãy xem [lens] (http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio) thay thế. –

Trả lời

115

Có, có cách hay để cập nhật các trường bản ghi. Trong GHCi bạn có thể làm -

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

Phần mở rộng 'RecordWildCards' cũng có thể tốt đẹp, để“ giải nén ”các trường trong phạm vi. Đối với các bản cập nhật, nó không hoàn toàn tốt đẹp: 'incrementA x @ Foo {..} = x {a = succ a}' –

+1

BTW, trong Frege (một Haskell cho JVM), bạn sẽ định nghĩa hàm là '' 'updateFoo x = x. {c = "Tạm biệt"} '' '(lưu ý toán tử' '' .'''). – 0dB

28

Đây là một công việc tốt cho lenses:

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

test = Foo 1 2 "Hello" 

Sau đó:

setL c "Goodbye" test 

sẽ cập nhật trường 'c' của 'thử' để bạn chuỗi.

+4

Và các gói giống như thấu kính thường xác định các toán tử ngoài các chức năng nhận và thiết lập các trường. Ví dụ, 'test $ c. ~" Goodbye "' là cách 'lens' sẽ làm như thế nào iirc. Tôi không nói rằng điều này là mang tính intutitive, nhưng một khi bạn biết các nhà khai thác thì tôi hy vọng nó sẽ dễ dàng như '$'. –

+2

Bạn có biết _setL_ đã đi đâu không? Tôi đang nhập _Control.Lens_, nhưng ghc đang báo cáo rằng _setL_ là không xác định. – dbanas

Các vấn đề liên quan