2015-07-05 94 views
1

我已经尝试了无数谷歌搜索的答案,但是对哈斯克尔来说很新,我不明白我找到的一半东西,另一半只是不太相关。Haskell不能推断类型?

我的问题是这样的,如果我跑了ghci这些语句

Prelude> let x = 5 :: (Num a) => a 
Prelude> sqrt x 

我得到了我期望

2.23606797749979 

但是,如果我把这个文件和编译(当然是我“M这里做的是相当琐碎)

sqrtNum :: (Num a, Floating b) => a -> b 
sqrtNum x = sqrt x 

我得到这个

myfile.hs:2:18: 
    Could not deduce (a ~ b) 
    from the context (Num a, Floating b) 
     bound by the type signature for 
       sqrtNum :: (Num a, Floating b) => a -> b 
     at test2.hs:1:12-40 
     `a' is a rigid type variable bound by 
      the type signature for sqrtNum :: (Num a, Floating b) => a -> b 
      at test2.hs:1:12 
     `b' is a rigid type variable bound by 
      the type signature for sqrtNum :: (Num a, Floating b) => a -> b 
      at test2.hs:1:12 
    Relevant bindings include 
     x :: a (bound at test2.hs:2:9) 
     sqrtNum :: a -> b (bound at test2.hs:2:1) 
    In the first argument of `sqrt', namely `x' 
    In the expression: sqrt x 

该问题可能非常简单,我只是监督它(因为这是我遇到的每一个其他错误的经验),但这只是不点击。

在此先感谢!

+1

您的类型声明可以将一种类型的数字“a”转换为另一种类型的“b”。但'sqrt'不这样做。 –

回答

7

你说的是你有一个从数字a到浮动b的函数。 sqrt函数需要一个浮点类型作为输入,但你只能保证Num。这里的开方类型:

Main> :t sqrt 
sqrt :: Floating a => a -> a 

所以,让我们复制开方和浮动浮动使这个FTN:

sqrtNum :: (Num a, Floating a) => a -> a 
sqrtNum x = sqrt x 

我离开了民,虽然只需要浮动。 Floating is a Fractional, and Fractional is a Num.

3

如果这还不够清楚,让我们先看看“引擎盖下”。类型类是一种语法糖的形式,Haskell在类型级别存储函数库。因此Typeclass约束可以简单地作为附加的参数来实现,这些参数可以隐式传递。例如,如果我写:

class Truthy a where 
    truthy :: a -> Bool 

instance Truthy Integer where 
    truthy = (== 0) 

instance Truthy Bool where 
    truthy = id 

那么我们可以这样定义一个函数:

maybeTruthy :: Truthy x => x -> Maybe x 
maybeTruthy x | truthy x = Just x 
       | otherwise = Nothing 

这里的关键是,我做的是完全一样的,因为这稍微令人费解的代码:

data Truthifier x = Truthifier {truthify :: x -> Bool} 

boolTruthifier :: Truthifier Bool 
boolTruthifier = Truthifier id 

integerTruthifier :: Truthifier Integer 
integerTruthifier = Truthifier (== 0) 

maybeTruthified :: Truthifier x -> x -> Maybe x 
maybeTruthified lib x | truthify lib x = Just x 
         | otherwise  = Nothing 

唯一的区别是,Haskell有有效的约束,例如,boolTruthifierBool类型,所以我并不需要显式传递给maybeTruthy,因为它通过参数的类型Bool来“乘坐”。上面我可以很容易地定义notTruthifier = Truthifier not,我可以用maybeTruthified notTruthifier而不是maybeTruthified boolTruthifier开始做事。例如,为什么Haskell默认禁止instance (Num a) => Truthy a,而你必须改写newtype TruthNum x = TruthNum x,然后instance (Num a) => Truthy (TruthNum a):Haskell必须有一个顶级类型来注册该函数库;如果你给它(Num a) => Truthy a那么它有没有更好的地方把它比a - 也就是说,所有的功能 - 而在后一种情况下,把它直接作用于TruthNum类型和只使用它时,x也有字典为Num功能。

如何sqrt适合所有这一切:在GHCI你会发现的sqrt类型是:

Prelude> :t sqrt 
sqrt :: Floating a => a -> a 

换句话说,sqrt可以在任何类型的值来完成,如果该类型为其定义了Floating字典。其sqrt返回相同类型的值,因为签名是a -> a

您试过写(Num a, Floating b) => a -> b。这是比定义实际允许的更宽容的类型。