7

我想创建一个元组,它包含一个箭头和一个描述箭头的字符串。如果我使用函数(而不是箭头)这样做,则以下工作如预期:

funTimes10 = (*10)
describe10 = "times 10"

tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10

我可以使用 访问该函数fst,并snd获得该函数的描述字符串。

但是,如果我用箭头交换函数,如下所示:

aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10
  • fst仍然有效并返回我的箭头,但是
  • 我没有得到任何描述字符串snd

我只收到此错误消息:

Ambiguous type variable `a0' in the constraint:
  (Arrow a0) arising from a use of `aTuple10'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `snd', namely `aTuple10'
In the expression: (snd aTuple10)
In an equation for `it': it = (snd aTuple10)

为什么我会收到这个错误,我应该怎么做才能避免它?

4

2 回答 2

9

让我们看看类型snd

snd :: (foo, x) -> x

(为了清楚起见,我重命名了类型变量)

类型说明的是,对于具有类型foo和的元组x,返回一些类型x。这里要知道的重要一点是,价值体系又名。Haskell 中的 runtime 是惰性的,Haskell 的类型系统是严格的,这意味着可以调用foox必须知道的类型。snd

在第一种情况下,当您只有 a 时Num b => (b -> b, String),调用snd会留下b歧义,因为您没有在任何地方提及它的具体类型,并且它不能从返回类型推断出来,因为foo ~ b它与x. 换句话说:因为(b, b)可以是任何数字类型的元组,并且类型检查器无法确定是哪一个,所以它是模棱两可的。这里的诀窍是我们将启动 Haskell 的默认规则,该规则规定如果数字类型不明确,它应该默认为Integer. 如果你用 开启了警告-Wall,它会说这正在发生。所以,我们的类型变成(Integer -> Integer, String)并且snd可以被调用。

然而,在第二种情况下,我们仍然设法b通过默认规则进行推断,但是 没有默认值Arrowa所以我们被卡住了!您必须明确指定您想要的箭头才能继续!您可以通过首先使用aTuple10其他地方的值来做到这一点:

let bla = aTuple10  -- We do this because `aTuple10` can have type variables, but `bla` cannot (by default)
fst bla (23 :: Int) -- This fixes the type of `bla`, so that `a ~ (->)` and `b ~ Int`
print $ snd bla     -- So the arrow isn't ambiguous here

...或者您可以只指定您想要的类型:

print $ snd (aTuple10 :: (Int -> Int, String))

PS如果你想改变模糊数字的默认类型,default关键字可以帮助你。

于 2012-02-27T13:59:03.423 回答
-1

我试图编译这个:

import Control.Arrow

funTimes10 = (*10)
describe10 = "times 10"

tuple10 :: (Num b) => ((b -> b), String)
tuple10 = (,) funTimes10 describe10

aTuple10 :: (Arrow a, Num b) => (a b b, String)
aTuple10 = (,) (arr funTimes10) describe10

但我明白了:

Could not deduce (b ~ Integer)
from the context (Arrow a, Num b)
  bound by the type signature for
             aTuple10 :: (Arrow a, Num b) => (a b b, String)
  at D:\dev\haskell\arr_tuple.hs:10:1-42
  `b' is a rigid type variable bound by
      the type signature for
        aTuple10 :: (Arrow a, Num b) => (a b b, String)
      at D:\dev\haskell\arr_tuple.hs:10:1
Expected type: b -> b
  Actual type: Integer -> Integer
In the first argument of `arr', namely `funTimes10'
In the first argument of `(,)', namely `(arr funTimes10)'

所以,我的猜测是您需要决定要使用哪个箭头实例。即,您可能需要arr funTimes使用注释指定具体类型。

于 2012-02-27T13:59:25.050 回答