簡體   English   中英

在 haskell 的 typeclass 中專門使用一種方法?

[英]Specialize one method in typeclass in haskell?

我正在編寫一種類型,我希望能夠根據內部類型的類型類實例化來更改方法的行為。

例如,考慮一下:

class Reduceable a where
    reduce :: a -> a
    -- Other methods not relevant here

instance Reduceable [[a]] where
    -- Reduce a list by dropping empty lists in the front
    reduce = dropWhile null
    -- Other methods implemented

instance Reduceable [a] => Reduceable [[a]] where
    -- Reduce a list of reduceable things by dropping empty lists in the front
    -- and also reducing the elements of the list
    reduce = dropWhile null . map reduce
    -- Other methods identical to Reduceable [[a]]

在這種情況下,我可以使用 OverlappingInstances 來使這段代碼工作。 但是,其他函數在某種程度上參與了它們的實現,並且不會根據類型而改變,因此我寧願不必多次實現它們(根據我對重疊實例的理解,這將是必需的)。

有沒有辦法在 Haskell 中得到我想要的東西?

一般來說,沒有一個很好的方法來做你所要求的。 稍微冗長但慣用的方法是在多個實例之間使用newtype到 select(如果存在)。 例如,您可以reduce newtype的新類型中:

newtype Don'tReduce a = Don'tReduce a
instance Reduceable (Don'tReduce a) where reduce = id

現在,您的instance Reduceable a => Reduceable [a]實例可以通過在調用reduce之前將其元素轉換為[Don'tReduce a]來“自下而上”。 這也為您提供了一些關於您認為底部在哪里的靈活性; 例如,這些可能都表現不同,其中任何一個在特定情況下都可能是合理的:

reduce :: Reduceable a => [[[[a]]]] -> [[[[a]]]]
reduce :: [[[[Don'tReduce a]]]] -> [[[[Don'tReduce a]]]]
reduce :: [[[Don'tReduce [a]]]] -> [[[Don'tReduce [a]]]]
reduce :: [[Don'tReduce [[a]]]] -> [[Don'tReduce [[a]]]]
reduce :: [Don'tReduce [[[a]]]] -> [Don'tReduce [[[a]]]]
reduce :: Don'tReduce [[[[a]]]] -> Don'tReduce [[[[a]]]]

您可以使用coerce在運行時在[[[[a]]]]和上述任何變體類型之間進行廉價(免費,優化)之間的轉換。

Reducable的第一個實例可以寫成:

instance Reduceable [[a]] where
    reduce = dropWhile null . map id

第二個是:

instance Reduceable [a] => Reduceable [[a]] where
    reduce = dropWhile null . map reduce

因此, reduce的形式為:

reduce = dropWhile null . map reduceElem

其中reduceElem:: [a] -> [a]可以是idreduce

所以讓我們給reduceElem自己的 class。

class ReducableElem a where
    reduceElem :: [a] -> [a]
    
instance {-# OVERLAPPING #-} ReducableElem [a] where
    reduceElem = reduce

instance {-# OVERLAPPABLE #-} ReducableElem a where
    reduceElem = id

然后我們只需要一個Reducable實例。

instance ReducableElem a => Reducable [[a]] where
    reduce = dropWhile null . map reduceElem 

測試一下:

λ> reduce [[],[],[1,2],[3,4]] :: [[Int]]    
[[1,2],[3,4]]

λ> reduce [[],[],[[],[1,2]],[[3,4],[5,6]]] :: [[[Int]]]
[[[1,2]],[[3,4],[5,6]]]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM