【问题标题】:How do I make a composed data constructor an instance of a class?如何使组合数据构造函数成为类的实例?
【发布时间】:2021-10-19 19:54:27
【问题描述】:

我已经声明了以下数据类型

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 = ...

我还希望PolyRatio 成为同一类的实例;我尝试了许多语法和语言扩展,但没有一个有效;比如:

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

我的目标是让substitutecomposeRatio (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))

*(其实我也改了不好的名字;但把它们留在这里以免混淆)

【问题讨论】:

标签: haskell


【解决方案1】:

首先...如果您想要该实例,那么该类的名称是错误的;两个多项式的商不是多项式。

其次,你甚至不能有实际多项式的实例,因为你确实需要至少 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 -&gt; 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 内函子。

【讨论】:

  • 谢谢! TypeFamilies 很好地解决了这个问题。我最终取消了Fractional 约束,转而支持Integral,将Domain 设为比率。 (为了清楚起见,我会将其附加到我的原始帖子中)
猜你喜欢
  • 2021-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
  • 2014-08-11
  • 2022-01-21
相关资源
最近更新 更多