如何创建一个类型类来表示包含可提取的“Num”实例类型的容器



一段时间以来,我一直在努力在Haskell的类型系统中表达某种模式。我甚至很难解释它(我想我对这个问题的理解还不够好,无法形成它),但它来了!(提前感谢任何能够理解并回答我问题的勇敢冒险家!)

让我们假设我们有两种不同的容器类型,ContFContD,它们都只是一个ADT,分别持有一个值FloatDouble(在本例中,它们也可能是新类型)。

我们想要编写一个多态函数,它适用于任何一种类型。也许它提取该值并将其加1(所以我们有一个Num约束)。因此,我们创建了一个类型类Cont,其中包含一个提取值的函数。

我们不能只将num原型作为num :: (Num n) => t -> n,因为那样我们会得到"无法推导Float~n"编译时错误;因此我们引入了一个关联类型族。

{-# LANGUAGE TypeFamilies #-}
data ContF = CF Float
data ContD = CD Double
class Cont t where
    type family ContNum t :: *
    num :: t -> ContNum t
instance Cont ContF where
    type ContNum ContF = Float
    num (CF f) = f
instance Cont ContD where
    type ContNum ContD = Double
    num (CD d) = d
contAdd1 :: (Cont t, Num n) => t -> n
contAdd1 t = num t + 1

然而,当我试图编译它时,我会得到以下错误。

Could not deduce (n ~ ContNum t)
from the context (Cont t, Num n)
  bound by the type signature for contAdd1 :: (Cont t, Num n) => t -> n

也许我想问的是:如何创建一个类型类来表示包含可提取Num实例类型的容器?此外,请注意,这是一个非常做作的例子,用来展示我希望理解的内容。

答案在错误消息中。您需要以某种方式告诉编译器n实际上是ContNum

你可以做

contAdd1:: (Cont t, Num n, n ~ ContNum t) => t -> n

或者根本不使用n

contAdd1 :: (Cont t, Num (ContNum t)) => t -> ContNum t

但最后一个需要FlexibleContexts扩展。

这是你问题的第一部分,如何使它编译。回答您关于如何在类型类级别移动约束的问题?只需添加即可。它有效:-)

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
data ContF = CF Float
data ContD = CD Double
class Num (ContNum t) =>  Cont t where
    type family ContNum t :: *
    num :: t -> ContNum t
instance Cont ContF where
    type ContNum ContF = Float
    num (CF f) = f
instance Cont ContD where
    type ContNum ContD = Double
    num (CD d) = d
contAdd1 :: (Cont t) => t -> ContNum t
contAdd1 t = num t + 1

> contAdd1 (CF 4)
 5.0

不知道如何使用这些新奇类型的家族来实现这一点,但有了fundeps,一切都很容易。

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
data ContF = CF Float
data ContD = CD Double
class Num n => Cont t n | t → n where
    num :: t → n
instance Cont ContF Float where
    num (CF f) = f
instance Cont ContD Double where
    num (CD d) = d
contAdd1 :: (Cont t n) => t → n
contAdd1 t = num t + 1

我怀疑这种类型的家庭应该比普通家庭更强大,但我对他们还不够了解。

最新更新