2012-02-04 49 views
3

我可以創建和參考相的指針使用爲結構用C成員++的::*.*,和->*語法,如:Haskell有記錄成員的指針/引用嗎?

char* fstab_t::*field = &fstab_t::fs_vfstype; 
my_fstab.*field = ... 

在Haskell,我可以很容易地創建用於記錄吸氣劑像臨時標籤:

(idxF_s,idxL_s) = swap_by_sign sgn (idxF,idxL) ; 

據我所知,我卻無法再更新使用這些干將記錄像標籤:

a { idxF_s = idxL_s b } 

有沒有簡單的方法來做到這一點,而無需編碼每個記錄二傳手?

+1

指向成員操作符的指針不是C而是C++。重新標記。 – 2012-02-04 20:08:21

回答

10

以一流價值捆綁在一起的吸氣劑和二聚體被稱爲透鏡。這樣做有相當多的軟件包;最受歡迎的是data-lensfclabels。這個previous SO question是一個很好的介紹。

這兩個庫都支持使用Template Haskell(使用數據鏡頭,爲便攜性提供an additional package)從記錄定義中獲取鏡頭。你的榜樣將被表示爲(使用數據鏡頭語法):

setL idxF_s (b ^. idL_s) a 

(或等價:idxF_s ^= (b ^. idL_s) $ a

你可以,當然,通過改變他們的getter和setter一起變換鏡頭的通用方式:

-- I don't know what swap_by_sign is supposed to do. 
negateLens :: (Num b) => Lens a b -> Lens a b 
negateLens l = lens get set 
    where 
    get = negate . getL l 
    set = setL l . negate 

(或等效:negateLens l = iso negate negate . l

在屬l,我會建議在任何時候不得不處理任何不平凡的記錄處理時使用鏡頭;它們不僅極大地簡化了記錄的純轉換,而且這兩個軟件包都包含便捷功能,用於使用鏡頭訪問和修改狀態monad的狀態,這非常有用。 (對於數據的鏡頭,你會希望使用data-lens-fd包在任何MonadState使用這些方便的功能;再次,他們是在一個單獨的包的可移植性。)


使用時無論是包,你應該開始您的模塊:

import Prelude hiding (id, (.)) 
import Control.Category 

這是因爲他們使用的前奏的id(.)功能廣義形式 - id可以作爲任何值鏡頭本身(而不是所有的有用的,誠然)和(.)用於組成鏡片(例如, getL (fieldA . fieldB) agetL fieldA . getL fieldB $ a相同)。較短的negateLens定義使用此。

5

你在這裏想要的是一流的唱片公司,儘管這種語言不存在,但Hackage上有幾個軟件包實現了這種模式。其中之一是fclabels,它可以使用模板Haskell爲您生成所需的樣板。下面是一個例子:

{-# LANGUAGE TemplateHaskell #-} 

import Control.Category 
import Data.Label 
import Prelude hiding ((.)) 

data Foo = Foo { _fieldA :: Int, _fieldB :: Int } 
    deriving (Show) 

$(mkLabels [''Foo]) 

main = do 
    let foo = Foo 2 3 

    putStrLn "Pick a field, A or B" 
    line <- getLine 

    let field = (if line == "A" then fieldA else fieldB) 

    print $ modify field (*10) foo