如何在以下非常简单的函数中解决此类实例错误?

ejo*_*o13 0 haskell types

我想实现一个简单的RestrictedTypeclass,它有两个函数lowerBoundupperBound,每个函数都接受一个Restricted实例并返回一个Num

\n
class Restricted r where\n    lowerBound :: (Num n) => r -> n\n    upperBound :: (Num n) => r -> n\n
Run Code Online (Sandbox Code Playgroud)\n

我正在尝试使用以下类型创建此类型类的实例OrthogonalClass

\n
instance Restricted OrthogonalClass where\n    lowerBound p = orthogonalLowerBound p\n    upperBound p = orthogonalUpperBound p\n
Run Code Online (Sandbox Code Playgroud)\n

在哪里

\n
orthogonalLowerBound :: (Num a) => OrthogonalClass -> a\northogonalLowerBound Legendre = a\n    where a = (-1.0) :: Double\n-- orthogonalLowerBound Hermite = NegInf\n
Run Code Online (Sandbox Code Playgroud)\n

(-1.0)是 aDouble并且它应该是可接受的返回值,因为 aDouble是 的实例Num。但是,我从编译器中收到以下错误:

\n
Polynomials.hs:20:33: error:\n    \xe2\x80\xa2 Couldn't match expected type \xe2\x80\x98a\xe2\x80\x99 with actual type \xe2\x80\x98Double\xe2\x80\x99\n      \xe2\x80\x98a\xe2\x80\x99 is a rigid type variable bound by\n        the type signature for:\n          orthogonalLowerBound :: forall a. Num a => OrthogonalClass -> a\n        at Polynomials.hs:19:1-55\n    \xe2\x80\xa2 In the expression: a\n      In an equation for \xe2\x80\x98orthogonalLowerBound\xe2\x80\x99:\n          orthogonalLowerBound Legendre\n            = a\n            where\n                a = (- 1.0) :: Double\n    \xe2\x80\xa2 Relevant bindings include\n        orthogonalLowerBound :: OrthogonalClass -> a\n          (bound at Polynomials.hs:20:1)\n   |\n20 | orthogonalLowerBound Legendre = a\n   |                                 ^\n
Run Code Online (Sandbox Code Playgroud)\n

我可以通过更改为来解决此(-1.0)问题(-1)orthogonalLowerBound但是,当我取消注释matchesHermite和 returns的第二个模式时,这对我没有帮助,它是作为数字实例的NegInf数据类的构造函数。Inf

\n

我的困惑就在这里。ADouble是 a 的实例Num,那么为什么我不能Double在函数中返回 a orthogonalLowerBound?为什么我不能返回 an Infwhich 是 a 的实例Num

\n

我缺少什么?

\n

这是 的完整定义OrthogonalClassInf如果您需要更多信息

\n
data OrthogonalClass = Legendre | Laguerre | Hermite | Tchebychev\n
Run Code Online (Sandbox Code Playgroud)\n
-- Playing around with infinity\ndata Inf = NegInf | PosInf | Undef | Finite deriving (Show)\n\ninstance Num Inf where\n    (+) a b = infAdd a b\n    (-) a b = infSub a b\n    (*) a b = infMult a b\n    signum a = infSignum a\n    abs a = infAbs a\n    fromInteger a = infFromInt a\n\ninfAdd :: Inf -> Inf -> Inf\ninfAdd NegInf NegInf = NegInf\ninfAdd PosInf PosInf = PosInf\ninfAdd PosInf NegInf = Undef\ninfAdd NegInf PosInf = Undef\ninfAdd Undef _ = Undef\ninfAdd _ Undef = Undef\ninfAdd NegInf Finite = NegInf\ninfAdd PosInf Finite = PosInf\ninfAdd Finite Finite = Finite\n\ninfSub :: Inf -> Inf -> Inf\ninfSub NegInf NegInf = Undef\ninfSub PosInf PosInf = Undef\ninfSub PosInf NegInf = PosInf\ninfSub NegInf PosInf = NegInf\ninfSub Undef _ = Undef\ninfSub _ Undef = Undef\ninfSub NegInf Finite = NegInf\ninfSub PosInf Finite = PosInf\ninfSub Finite Finite = Finite\n\ninfMult :: Inf -> Inf -> Inf\ninfMult NegInf NegInf = PosInf\ninfMult PosInf PosInf = PosInf\ninfMult PosInf NegInf = NegInf\ninfMult NegInf PosInf = NegInf\ninfMult Undef _ = Undef\ninfMult _ Undef = Undef\ninfMult NegInf Finite = NegInf\ninfMult PosInf Finite = PosInf\ninfMult Finite Finite = Finite\n\ninfAbs :: Inf -> Inf\ninfAbs NegInf = PosInf\ninfAbs PosInf = PosInf\ninfAbs Undef  = Undef\ninfAbs Finite = Finite\n\ninfSignum :: (Num a) => Inf -> a\ninfSignum NegInf = (-1)\ninfSignum PosInf = 1\ninfSignum Undef = 0\ninfSignum Finite = 0\n\ninfFromInt :: (Integral i) => i -> Inf\ninfFromInt x = Finite\n
Run Code Online (Sandbox Code Playgroud)\n

Fyo*_*kin 6

这是关于泛型类型方向的一个非常常见的混淆。

简而言之:是函数的调用者选择泛型类型,而不是实现者。

如果您有一个带有此签名的函数:

orthogonalLowerBound :: (Num a) => OrthogonalClass -> a
Run Code Online (Sandbox Code Playgroud)

该签名说:嘿,你,无论谁调用我的函数!选择一种类型。任何类型。我们就这样称呼它吧a。现在确保有一个实例Num a。完毕?伟大的!现在我可以向您返回该类型的值a

此类型签名是对调用该函数的人的承诺,而您(该函数的实现者)必须履行该承诺。无论调用者选择什么类型,您都必须返回该类型的值。

调用者可以选择任何具有Num实例的类型,例如:

o :: OrthogonalClass
o = ...

x :: Int
x = orthogonalLowerBound o

y :: Decimal
y = orthogonalLowerBound o
Run Code Online (Sandbox Code Playgroud)

解决方案?如果您的函数应该返回 a Double,只需在其类型签名中说明即可:

orthogonalLowerBound :: OrthogonalClass -> Double
Run Code Online (Sandbox Code Playgroud)

当然,在这种情况下,您不能 return Inf,这应该是这样:函数不能根据参数的值返回不同的类型。此功能称为“依赖类型”,Haskell 不直接支持它。

如果您确实需要无穷大,该Double类型也包含它,并且有多种方法可以将其作为值获取。例如从包装上看一下infinityieee754