sch*_*ine 7 floating-point haskell
根据Hackage,这些RealFloat
类的功能是
......常数函数[s] ...
如果它们始终保持相同的值,无论参数如何,如本说明所示,为什么不简单地使用:
class (RealFrac a, Floating a) => RealFloat a where
floatRadix :: Integer
floatDigits :: Int
floatRange :: (Int, Int)
...
Run Code Online (Sandbox Code Playgroud)
lef*_*out 11
您提出的非功能方法将具有类型
floatRadix' :: RealFloat a => Integer
floatDigits' :: RealFloat a => Int
...
Run Code Online (Sandbox Code Playgroud)
那些是不明确的类型:有一个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)
Run Code Online (Sandbox Code Playgroud)
*Main> floatDigits' :: Int <interactive>: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 <interactive>: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
Run Code Online (Sandbox Code Playgroud)
这个问题是你要为多个实例构造函数,比如:
instance RealFloat Float where
-- ...
floatRadix = 2
floatDigits = 24
floatRange = (-125, 128)
instance RealFloat Double where
-- ...
floatRadix = 2
floatDigits = 53
floatRange = (-1021, 1024)
Run Code Online (Sandbox Code Playgroud)
但是现在它在您查询示例时会产生问题floatDigits
:我们应该采取什么样的实例?一个用于Float
,或一个用于Double
(或另一种类型的)?所有这些都是有效的候选人.
通过使用a
参数,我们可以消除歧义,例如:
Prelude> floatDigits (0 :: Float)
24
Prelude> floatDigits (0 :: Double)
53
Run Code Online (Sandbox Code Playgroud)
但它认为参数的值无关紧要,例如:
Prelude> floatDigits (undefined :: Float)
24
Prelude> floatDigits (undefined :: Double)
53
Run Code Online (Sandbox Code Playgroud)
班级RealFloat
很老了。当它被设计时,没有人找到真正好的方法来将额外的类型信息传递给函数。当时,采用相关类型的参数并期望用户传递undefined
该类型是很常见的。正如 leftaroundabout 所解释的,GHC 现在的扩展在大多数情况下都可以很好地完成此任务。但在此之前TypeApplications
,还发明了另外两种技术来更干净地完成这项工作。
要在没有 GHC 扩展的情况下消除歧义,您可以使用代理传递或基于新类型的标记。我相信这两种技术都是由 Edward Kmett 赋予的最终形式,并由 Shachaf Ben-Kiki 进行最后的多态旋转(参见谁发明了代理传递以及何时发明的?)。代理传递往往会提供易于使用的 API,而新类型方法在某些情况下可能会更有效。这是代理传递方法。这要求您传递某种类型的参数。传统上,调用者将使用Data.Proxy.Proxy
,其定义为
data Proxy a = Proxy
Run Code Online (Sandbox Code Playgroud)
以下是使用代理传递时该类的外观:
class (RealFrac a, Floating a) => RealFloat a where
floatRadix :: proxy a -> Integer
floatDigits :: proxy a -> Int
...
Run Code Online (Sandbox Code Playgroud)
下面是它的使用方法。请注意,无需传入您正在讨论的类型的值;你只需传递代理构造函数。
foo :: Int
foo = floatDigits (Proxy :: Proxy Double)
Run Code Online (Sandbox Code Playgroud)
为了避免传递运行时参数,您可以使用标记。这通常是通过tagged
包完成的,但自己推出也很容易。您甚至可以重用Control.Applicative.Const
,但这并不能很好地传达意图。
newtype Tagged t a = Tagged
{ unTagged :: a }
Run Code Online (Sandbox Code Playgroud)
该类的外观如下:
class (RealFrac a, Floating a) => RealFloat a where
floatRadix :: Tagged a Integer
floatDigits :: Tagged a Int
...
Run Code Online (Sandbox Code Playgroud)
下面是你如何使用它:
foo :: Int
foo = unTagged (floatDigits :: Tagged Double Int)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
142 次 |
最近记录: |