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

时间:2015-01-08 18:52:42

标签: haskell types

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

GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
Prelude> let x = 1
Prelude> let y = 2

xy都有Num a => a类型。但(/)中没有定义Num!那么为什么表达式x / y类型检查?

Prelude> x / y
0.5

(/)在课程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)

如果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

3 个答案:

答案 0 :(得分:6)

您似乎正在使用较新版本的ghci,默认情况下,该版本启用了NoMonomorphismRestriction。在这种情况下,xy确实有Num a => a类型:

Prelude> :set -XNoMonomorphismRestriction
Prelude> let x = 1
Prelude> let y = 2
Prelude> :t x
x :: Num a => a

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

Prelude> :t x/y
x/y :: Fractional a => a

由于NumFractional的超类,因此任何Fractional类型也是Num类型,因此专门针对x和{{1}的类型} y是可能的。这与做类似的事情没有什么不同:

Fractional a => a

函数($) = id :: (a -> b) -> (a -> b) 只是$ id :: c -> c的特化。在您的情况下,您正在专门化一个约束类型,并且约束可以通过子类替换父类(即更一般地使用更具体的约束),因此c = a -> bFractional a => a的特化。

当ghci必须输出结果时,必须选择 Num a => a运算符的 来计算结果,因此它必须实例化键入具体类型。这是由defaulting完成的,因此执行的操作是/实例的操作,但可以使用Double声明更改它们。


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

  

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

Num
     

其中default (t1 , ... , tn) ,每个n>=0必须是ti所持有的类型。在   发现模糊类型的情况,模糊类型   变量Num ti在以下情况下是可以违约的:

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

答案 1 :(得分:0)

如果xy的类型为Num a => a,则表示它们具有多态性。它并不代表某种类型,你所知道的只是它是Num&#39;的一个实例,但是&#39;任何类型,只要它& #39;是Num&#39;的一个实例。因此,x / y只要有NumFractional的实例,就会有任何类型,因为Fractional是一个子类Num是任何类型,只要它是Fractional的实例,其类型如RationalDouble就满足。

顺便说一句,1 / 2字面意思也会进行类型检查,原因与(例如)1 :: Double2 :: Double类型检查:Haskell中的1不是&# 39; t限于整数类型,但可用于任何数字类型。

答案 2 :(得分:-1)

Haskell会将分子转换为Fractional并执行分数除法。如果您需要划分Int,请尝试使用中缀运算符div

Prelude> x div y