在 haskell 中专门化类型类中的一种方法?

Jar*_*len 2 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]]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我可以使用 OverlappingInstances 来使该代码正常工作。然而,其他函数在某种程度上参与了它们的实现,并且不会根据类型而改变,因此我宁愿不必多次实现它们(根据我对重叠实例的理解,这是必需的)。

有没有办法在 Haskell 中得到我想要的东西?

Dan*_*ner 6

一般来说,没有一个真正好的方法可以满足您的要求。稍微冗长但惯用的方法是newtype在多个实例存在时在多个实例之间进行选择。例如,您可以将元素包装在for 中newtype,但 forreduce不起作用:

newtype Don'tReduce a = Don'tReduce a
instance Reduceable (Don'tReduce a) where reduce = id
Run Code Online (Sandbox Code Playgroud)

现在,您的实例可以通过在调用之前将其元素转换为 sinstance Reduceable a => Reduceable [a]来“触底” 。这也让您可以灵活地考虑底部的位置;例如,这些行为可能都不同,并且其中任何一个在特定情况下都可能是合理的:[Don'tReduce a]reduce

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]]]]
Run Code Online (Sandbox Code Playgroud)

您可以使用它在运行时便宜地(免费,启用优化)在上述任何变体类型coerce之间进行转换。[[[[a]]]]