我声明了以下数据类型
data Poly a = Poly [a]
还有一个类:
class Polynom p where
substitute :: p a -> a -> a
compose :: p a -> p a -> p a
我可以使数据类型成为类的一个实例:
instance Polynom Poly where
substitute = ...
compose = ...
我还希望 Poly
的 Ratio
是同一类的实例;我尝试了很多语法和语言扩展,但都不起作用;像这样的事情:
instance Polynom (Ratio . Poly) where ...
-- error: cannot use (.) there
instance Poly p => Polynom (Ratio (p _)) where ...
-- error: no wildcards allowed
type X a = Ratio (Poly x)
instance Polynom X where ...
-- error: X needs another param
instance Polynom (* -> Ratio (Poly *)) where ...
-- error: wrong kind
我的目标是能够让 substitute
和 compose
在 Ratio (Poly *)
上工作;例如:
rf1 = Poly [1,2,3] % Poly [4,5,6] :: Ratio (Poly Int)
rf2 = Poly [0,1] % Poly [1,0] :: Ratio (Poly Int)
rf = rf1 `compose` rf2 :: Ratio (Poly Int)
result = substitute rf 10 :: Int
这在 Haskell 中甚至可能吗?如果是这样,我在这里缺少什么语法或语言扩展?
更新
我使用 TypeFamilies 解决了这个问题;正如@leftaroundabout 建议的那样。工作类实例如下所示*:
instance Integral a => Polynom (Ratio (Poly a)) where
type Domain (Ratio (Poly a)) = Ratio a
substitute (n :% d) x = substitute ((%1) <$> n) x
/ substitute ((%1) <$> d) x
compose (n :% d) = substitute ((pure <$> n) % (pure <$> d))
*(我实际上也改了不好的名字;但为了避免混淆,把它们放在这里了)
最佳答案
首先……如果你想要那个实例,那么这个类的名字是错误的;两个多项式的商不是多项式。
其次,您甚至不能像类那样拥有实际多项式的实例,您至少需要 Num
约束。
class Polynom p where
substitute :: Num a => p a -> a -> a
compose :: Num a => p a -> p a -> p a
就是说,就 Haskell 而言,这里没有太多障碍。
.
显然不能在类型级别使用,但是有 Compose
这是一种等效的东西。
data Compose f g a = Compose { getCompose :: f (g a) }
这意味着用于组合仿函数,Ratio
不是†,但是我认为没有理由不只是用它来组合任意 Type -> 输入
内容。
instance Polynom (Compose Ratio Poly) where
substitute (r%d) = substitute r / substitute d
...此时您会发现 Num
约束还不够。不过,在 Polynomial
类中要求 Fractional
有点傻。
我建议您采用完全不同的方法。你可以使用像这样的类
{-# LANGUAGE TypeFamilies #-}
import Data.Kind (Type)
class Endofunction f where
type Domain f :: Type
evaluate :: f -> Domain f -> Domain f
compose :: f -> f -> f
然后实例是
instance Num a => Endofunction (Poly a) where
type Domain (Poly a) = a
...
并且,现在不需要 Compose
,
instance Fractional a => Endofunction (Ratio (Poly a)) where
type Domain (Ratio (Poly a)) = a
...
†我怀疑您实际上可以将其视为介于某些两个类别之间的仿函数,但它肯定不是 Hask 内仿函数。
关于haskell - 如何使组合数据构造函数成为类的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69621885/