作者:acChristina | 来源:互联网 | 2022-12-02 12:08
1> leftaroundab..:
您提出的非功能方法将具有类型
floatRadix' :: RealFloat a => Integer
floatDigits' :: RealFloat a => Int
...
那些是不明确的类型:有一个a
类型变量,但它实际上并不出现在右边,=>
因此不能从上下文中推断出来.也就是说,在标准的Haskell中,确实是推断这种类型变量的唯一方法:本地类型签名也只能是签名头,而不是约束.所以不管你写的(floatDigits' :: Int)
还是(floatDigits' :: RealFloat Double => Int)
,它不会实际工作-编译器不能推断出你的意思是instance RealFloat Double
该方法的版本.
class RealFloat' a where
floatDigits' :: Int
instance RealFloat' Double where
floatDigits' = floatDigits (0 :: Double)
*Main> floatDigits' :: Int
:3:1: error:
• No instance for (RealFloat' a0)
arising from a use of ‘floatDigits'’
• In the expression: floatDigits' :: Int
In an equation for ‘it’: it = floatDigits' :: Int
*Main> floatDigits' :: RealFloat Double => Int
:4:1: error:
• Could not deduce (RealFloat' a0)
arising from a use of ‘floatDigits'’
from the context: RealFloat Double
bound by an expression type signature:
RealFloat Double => Int
at :4:17-39
The type variable ‘a0’ is ambiguous
• In the expression: floatDigits' :: RealFloat Double => Int
In an equation for ‘it’:
it = floatDigits' :: RealFloat Double => Int
因此,Haskell不允许您首先编写具有模糊类型的方法.实际上,我在上面编写的时候尝试编译该类会给出以下错误消息:
• Could not deduce (RealFloat' a0)
from the context: RealFloat' a
bound by the type signature for:
floatDigits' :: forall a. RealFloat' a => Int
at /tmp/wtmpf-file3738.hs:2:3-21
The type variable ‘a0’ is ambiguous
• In the ambiguity check for ‘floatDigits'’
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
When checking the class method:
floatDigits' :: forall a. RealFloat' a => Int
In the class declaration for ‘RealFloat'’
然而,突出显示的行引用了一个GHC扩展,上面写着"没关系,我知道我在做什么".因此,如果您{-# LANGUAGE AllowAmbiguousTypes #-}
使用其中的文件顶部添加class RealFloat'
,编译器将接受它.
但是,当实例无法在使用站点解析时,重点是什么?那么,它可以真正得到解决,但只用一个漂亮的新GHC的扩展:
*Main> :set -XTypeApplications
*Main> floatDigits' @Double
53
2> Willem Van O..:
这个问题是你要为多个实例构造函数,比如:
instance RealFloat Float where
-- ...
floatRadix = 2
floatDigits = 24
floatRange = (-125, 128)
instance RealFloat Double where
-- ...
floatRadix = 2
floatDigits = 53
floatRange = (-1021, 1024)
但是现在它在您查询示例时会产生问题floatDigits
:我们应该采取什么样的实例?一个用于Float
,或一个用于Double
(或另一种类型的)?所有这些都是有效的候选人.
通过使用a
参数,我们可以消除歧义,例如:
Prelude> floatDigits (0 :: Float)
24
Prelude> floatDigits (0 :: Double)
53
但它认为参数的值无关紧要,例如:
Prelude> floatDigits (undefined :: Float)
24
Prelude> floatDigits (undefined :: Double)
53