我想要创建一个元组,它包含一个箭头和一个描述箭头的字符串。如果我使用函数(而不是箭头),下面的工作就像预期的那样:
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)
为什么我会收到此错误,我该怎么办,以避免它?
答案 0 :(得分:9)
让我们看一下snd
的类型:
snd :: (foo, x) -> x
(为了清楚起见,我重命名了类型变量)
类型指出,对于类型为foo
和x
的元组,返回x
类型的内容。这里要知道的重要事情是,虽然价值体系又名。 Haskell中的运行时是懒惰的,Haskell的类型系统是严格的,这意味着在foo
被调用之前必须知道x
和snd
的类型。
在第一种情况下,如果您只有Num b => (b -> b, String)
,则调用snd
会使b
不明确,因为您没有在任何地方提及其具体类型,而且它不能从返回类型推断,因为foo ~ b
与x
不同。换句话说:因为(b, b)
可以是任何数字类型的元组,并且类型检查器无法确定哪一个,它是不明确的。这里的诀窍是我们将Haskell的默认规则启动,这表明如果数字类型不明确,它应该默认为Integer
。如果您已使用-Wall
发出警告,则表示会发生这种情况。因此,我们的类型变为(Integer -> Integer, String)
,可以调用snd
。
但是,在第二种情况下,我们仍然设法通过默认规则推断b
,但Arrow
没有默认a
,所以我们被卡住了!您必须明确指定所需的箭头才能继续!您可以先在其他地方使用值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
keyword可以帮助您。
答案 1 :(得分:-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
。