为什么在Num中没有定义(/)时编译"1/2"?

Zhe*_*lov 4 haskell types

很抱歉有新手问题,但我真的不明白重载值:

GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Prelude> let x = 1
Prelude> let y = 2
Run Code Online (Sandbox Code Playgroud)

无论xy有型Num a => a.但是没有(/)定义Num!那么为什么表达式x / y检查呢?

Prelude> x / y
0.5
Run Code Online (Sandbox Code Playgroud)

(/)在课堂上定义Fractional.有一些隐式转换NumFractional

UPD:

因此,正如预期的那样,我得到的答案是人们声称这x / y a是专门的Fractional a => a.

我创建了自己的数字层次结构:

data MyInt = MyInt Integer deriving Show
data MyDouble = MyDouble Double deriving Show

class MyNum a where
    (+#) :: a -> a -> a -- + renamed to +# to avoid collision with standard +
    myFromInteger :: MyNum a => Integer -> a

class MyNum a => MyFractional a where
    (/#) :: a -> a -> a

instance MyNum MyInt where
    (MyInt a) +# (MyInt b) = MyInt (a + b)
    myFromInteger i = MyInt i

instance MyNum MyDouble where
    (MyDouble a) +# (MyDouble b) = MyDouble (a + b)
    myFromInteger i = MyDouble (fromInteger i)

instance MyFractional MyDouble where
    (MyDouble a) /# (MyDouble b) = MyDouble (a / b)
Run Code Online (Sandbox Code Playgroud)

如果asnwers中的所有内容都为true,Num则替换为的类似代码MyNum也应该有效.但ghci报告错误:

Prelude> :load myint.hs
*Main> let x = myFromInteger 1
*Main> let y = myFromInteger 2
*Main> x /# y

<interactive>:14:1:
    No instance for (MyFractional a0) arising from a use of `it'
    The type variable `a0' is ambiguous
    Note: there is a potential instance available:
      instance MyFractional MyDouble -- Defined at myint.hs:19:10
    In the first argument of `print', namely `it'
    In a stmt of an interactive GHCi command: print it
Run Code Online (Sandbox Code Playgroud)

Bak*_*riu 6

您似乎正在使用更新版本的ghci,默认情况下已NoMonomorphismRestriction启用.在这种情况下x,y确实有类型Num a => a:

Prelude> :set -XNoMonomorphismRestriction
Prelude> let x = 1
Prelude> let y = 2
Prelude> :t x
x :: Num a => a
Run Code Online (Sandbox Code Playgroud)

这种类型,因为它是多态的,专门用于Fractional a => a评估时x/y:

Prelude> :t x/y
x/y :: Fractional a => a
Run Code Online (Sandbox Code Playgroud)

由于Num是类的超类Fractional的任何Fractional类型也是一种Num类型并且因此专门的类型xyFractional a => a是可能的.这与做类似的事情没有什么不同:

($) = id :: (a -> b) -> (a -> b)
Run Code Online (Sandbox Code Playgroud)

该功能$只是一个特殊的id :: c -> c地方c = a -> b.在你的情况下,你是一个专门的约束类型,约束可以专门用子类替换父类(即更一般的更具体的约束),所以Fractional a => a是一个特殊的Num a => a.

当ghci中具有输出结果就必须选择一个实现了的/操作,以计算出结果,因此它必须实例化类型的具体类型.这是通过默认完成的,因此执行的操作是Double实例的操作,但可以使用default声明更改它们.


请注意,默认仅适用于内置类.引用上面的链接:

Num中的歧义是最常见的,因此Haskell提供了另一种解决方法 - 使用默认声明:

default (t1 , ... , tn)
Run Code Online (Sandbox Code Playgroud)

其中n>=0,每个ti必须是一个类型Num ti.在发现模糊类型的情况下,如果出现以下情况,则模糊类型变量v是可以违约的:

  • v仅出现在表单的约束中C v,其中C是一个类,并且这些类中的至少一个是数字类(即,Num或者是其子类Num),并且
  • 所有这些类都在一个Prelude或一个标准库中定义(图6.2--6.3,页面 - 显示数字类,图6.1,页面,显示了Prelude中定义的类.)