2011-10-22 109 views
5

爲了簡單起見,我將使用這個人爲的例子類(的一點是,我們從方法得出一些昂貴的數據):記憶化和類型類

class HasNumber a where 
    getNumber :: a -> Integer 
    getFactors :: a -> [Integer] 
    getFactors a = factor . getNumber 

當然,我們可以做memoizing實現這個類如:

data Foo = Foo { 
    fooName :: String, 
    fooNumber :: Integer, 
    fooFactors :: [Integer] 
} 

foo :: String -> Integer -> Foo 
foo a n = Foo a n (factor n) 

instance HasNumber Foo where 
    getNumber = fooNumber 
    getFactors = fooFactors 

但它似乎是需要有點難看的「因素」字段手動添加到,這將是一個HasNumber實例的任何記錄。下一步的想法:

data WithFactorMemo a = WithFactorMemo { 
    unWfm :: a, 
    wfmFactors :: [Integer] 
} 

withFactorMemo :: HasNumber a => a -> WithFactorMemo a 
withFactorMemo a = WithFactorMemo a (getFactors a) 

instance HasNumber a => HasNumber (WithFactorMemo a) where 
    getNumber = getNumber . unWfm 
    getFactors = wfmFactors 

這將需要大量的樣板的原始a的所有其他業務提升爲WithFactorMemo a,雖然。

是否有任何優雅的解決方案?

+0

我只是想到了另外一個解決辦法是讓*因素*功能memoizing,雖然這將是不太實際的,如果getNumber'的'結果是一些比較大的數據結構,(據我所知)的條目將永遠不會被垃圾收集(與我的問題中的兩個解決方案相反)。 – FunctorSalad

回答

7

這裏的解決方案:失去類型類。我已經談到了這個herehere。任何類型類別TC a,其每個成員都將單個a作爲參數與數據類型同構。這意味着,你HasNumber類的每個實例可以在這個數據類型來表示:

data Number = Number { 
    getNumber' :: Integer, 
    getFactors' :: [Integer] 
} 

也就是說,通過這種轉變:

toNumber :: (HasNumber a) => a -> Number 
toNumber x = Number (getNumber x) (getFactors x) 

而且Number顯然是HasNumber實例爲好。

instance HasNumber Number where 
    getNumber = getNumber' 
    getFactors = getFactors' 

這同構向我們展示了這個類是一種變相的數據類型,它應該死。改用Number。如何做到這一點可能最初並不明顯,但有一點經驗應該會很快出現。 。例如,您Foo類型變爲:然後

data Foo = Foo { 
    fooName :: String, 
    fooNumber :: Number 
} 

你的memoization會自由,因爲因子存放在Number數據結構。

+0

實際上,這就是我剛剛發佈之前就決定嘗試的東西:)我同意將操作放入單一類型(此處爲'Number'),但是也許有一個'HasNumber a'類仍然是個好主意numberDict :: a - > Number'連同包裝器'getNumber = getNumber'。 numberDict'等等。但是我們必須將'Number'存儲在要成爲'HasNumber'的記錄中,而不是在'numberDict'實現中從Integer創建'Number'(這當然會使我們不再記憶) 。 – FunctorSalad

+0

在這種情況下,我強烈建議不要使用類型類,它只會阻礙你。具體來說,FP工具箱更適合於這種編程,這種語言比抽象類更好地抽象數據類型,它不會讓你自己欺騙你正在做OO建模(你是不是 - 如果你這樣想,即使沒有意識到,語言最終會限制你的道路)。 – luqui