我试图定义一个非常简单的数据结构,假设将Infinity
元素添加到Num
下的任何类型。我还将它放在已定义的类NumContainer
下,该类具有使用常规fromNum
构造NumWithInf
的方法Num
。代码非常简单。
data NumWithInf a = Infinity | Finite a deriving Show
class NumContainer k where
fromNum :: Num a => a -> k
instance Num a => NumContainer (NumWithInf a) where
fromNum x = Finite x
然而,当我运行它时,GHCI给了我以下错误:
hw.hs:7:24:
Could not deduce (a ~ a1)
from the context (Num a)
bound by the instance declaration at hw.hs:6:10-45
or from (Num a1)
bound by the type signature for
fromNum :: Num a1 => a1 -> NumWithInf a
at hw.hs:7:5-24
`a' is a rigid type variable bound by
the instance declaration at hw.hs:6:10
`a1' is a rigid type variable bound by
the type signature for fromNum :: Num a1 => a1 -> NumWithInf a
at hw.hs:7:5
In the first argument of `Finite', namely `x'
In the expression: Finite x
In an equation for `fromNum': fromNum x = Finite x
Failed, modules loaded: none.
据我所知,它表示x
中的Finite x
与签名a
中的fromNum :: Num a => a -> k
的类型不一定相同。我该如何指定?
答案 0 :(得分:5)
一个简单的解决方案(即不使用花哨类型系统欺骗的解决方案)使您的班级使用类型* -> *
而不是*
。实际上,这只是意味着你将其定义为:
class NumContainer k where
fromNum :: Num a => a -> k a -- Result type parametrised on `a`
然后该实例变为:
instance NumContainer NumWithInf where
fromNum x = Finite x
请注意,没有地方可以在实例中放置Num
约束。无论如何这都是不必要的 - fromNum
类型中的约束已经足够好了。
答案 1 :(得分:2)
问题是您尝试将fromNum
从任意Num
定义到任何其他Num
,这是不可能的。你想要像
fromNum x = Finite (toNum x)
其中toNum
将x
转换为正确的Num
。在一般情况下这是不可能的。但是,您的容器实际上是一个应用仿函数,您的函数fromNum
(签名较窄a -> k a
)只是pure
。
此外,您可以轻松定义Num
的{{1}}个实例,然后您可以将NumContainer
实现为
fromInteger
现在可以进行转换,因为您不是从任意frommInteger a = Finite (fromInteger a)
开始,而是从Num
开始。
另请注意,目前只有一个Integer
您的类型与Infinite
同构。
答案 2 :(得分:0)
为什么需要类型类?通常需要类型类来根据类型重载函数。因此,除非您计划使用不同的容器,否则您可能不需要类型类,而只能执行
fromNum :: Num a => a -> NumWithInf a
fromNum = Finite
但是,您的问题“当存在类型类限制时,如何在实例语句中指定类型?”您可以使用MultiParamTypeClasse
执行此操作,并将a
作为类型类的参数传递。
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
data NumWithInf a = Infinity | Finite a deriving Show
class NumContainer a k where
fromNum :: Num a => a -> k
instance Num a => NumContainer a (NumWithInf a) where
fromNum x = Finite x