[英]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]
可以是id
或reduce
。
所以讓我們給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.