function :: (Floating a, RealFrac a, Integral b) => a -> b
function x = floor (sqrt x)
Run Code Online (Sandbox Code Playgroud)
好的,所以如果你看一下这个函数,我指定的a可以是两个RealFrac和FloatingTypeclasses,然后b是一个Integral.这是因为签名floor和sqrt:
floor :: (Integral b, RealFrac a) => a -> b
sqrt :: Floating a => a -> a
Run Code Online (Sandbox Code Playgroud)
可以看出sqrt只需要花费Floating而且floor只需要花费RealFrac.所以我设置a为RealFrac和Floating.然后我指定那b是Integral因为floor给了我们一个Integral.
所以我的问题是
newfunction :: (Integral a, RealFrac a, Integral b) => a -> b
newfunction a = floor (sqrt (fromIntegral a))
Run Code Online (Sandbox Code Playgroud)
为什么这不起作用?
实际的正确类型签名是
newfunction :: (Integral a, Integral b) => a -> b
Run Code Online (Sandbox Code Playgroud)
为什么这不起作用?
......但它确实:
Prelude> :{
Prelude| let newfunction :: (Integral a, RealFrac a, Integral b) => a -> b
Prelude| newfunction a = floor (sqrt (fromIntegral a))
Prelude| :}
Prelude> :t newfunction
newfunction :: (Integral a, Integral b, RealFrac a) => a -> b
Run Code Online (Sandbox Code Playgroud)
只是如果你让GHC自动推断出类型签名,它会为你提供一个更简单/更好的签名:
Prelude> let newfunction a = floor (sqrt (fromIntegral a))
Prelude> :t newfunction
newfunction :: (Integral b, Integral a) => a -> b
Run Code Online (Sandbox Code Playgroud)
但这并不意味着手动指定的一个是错误的 - 它可能不是那么普遍,可能会或可能不会是您所追求的,具体取决于具体情况.
至于什么对于更普遍的东西意味着什么呢?当它做出更少的假设并减少对其输入的要求/约束时; 通过要求更少,它可以使用更多种类的输入,这被称为"更一般".
此外,请注意,在这种情况下较不通用的版本是无效的,因为你不能真正用anying调用它,但Haskell仍然允许你定义这样一个函数 - 失败将发生在调用站点.
Prelude> :i RealFrac
class (Real a, Fractional a) => RealFrac a where
...
-- Defined in ‘GHC.Real’
instance RealFrac Float -- Defined in ‘GHC.Float’
instance RealFrac Double -- Defined in ‘GHC.Float’
Prelude> :i Integral
class (Real a, Enum a) => Integral a where
...
-- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
Run Code Online (Sandbox Code Playgroud)
-看到一个类型如何不属于双方RealFrac并Integral在同一时间?如果你手动定义instance RealFrac Integer where ...,它会起作用,但这可能没有意义,并且可能会违反某些类型类法则,从而导致代码不一致/错误.
因此,作为一般准则:从GHC推断类型签名开始,然后只添加其他约束或使签名更加单态/更少多态.
此外,您还可以自由定义这些函数,我认为这些函数更具可读性.我已经在下面展示了如何将当前的括号内的版本转换为免费版本(也称为默认版本):
function x = floor (sqrt x)
function x = floor . sqrt $ x
function = floor . sqrt
newfunction a = floor (sqrt (fromIntegral a))
newfunction a = floor . sqrt . fromIntegral $ a
newfunction = floor . sqrt . fromIntegral
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
79 次 |
| 最近记录: |