2013-02-19 80 views
88

比方說,我有如下記錄ADT:在複製剩餘字段的同時分配記錄中單個字段的速記方式?

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

我想一個函數,它記錄並返回一個記錄(同類型),其中字段所有,但一個具有相同價值觀的一個傳遞作爲參數,就像這樣:

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

上述工作,但對於更多的字段的記錄(比如10),創造了這樣的功能將需要大量的輸入,我覺得完全沒有必要。

有沒有更簡單的方法來做同樣的事情?

+2

用於更新的記錄語法存在,但很快就會變得麻煩。請看[鏡頭](http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio)。 – 2013-02-19 13:15:28

回答

115

是的,有一個更新記錄字段的好方法。在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" } 
+4

'RecordWildCards'擴展名也可以很好,可以「解壓縮」範圍中的字段。對於更新,它不是很好:'incrementA x @ Foo {..} = x {a = succ a}' – 2013-02-19 14:14:50

+1

順便說一下,在Frege(一個用於JVM的Haskell)中,你可以將函數定義爲'''updateFoo x = x。{c =「Goodbye」}'''(注意''''.'''運算符)。 – 0dB 2016-02-06 14:34:05

28

這是lenses的工作:

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

test = Foo 1 2 "Hello" 

然後:

setL c "Goodbye" test 

將更新 '測試' 的領域 'C' 到您串。

+4

類似透鏡的軟件包通常除了獲取和設置字段的函數外,還定義了操作符。例如,'test $ c。〜'Goodbye''是'透鏡'如何做iirc。我並不是說這是直接的,但是一旦你知道了操作員,那麼我期望它會像'$'一樣容易。 – 2013-02-19 15:06:10

+2

你知道_setL_去哪了嗎?我正在導入_Control.Lens_,但ghc報告說_setL_未定義。 – dbanas 2017-08-14 13:12:49

相關問題