我想创建一个元组,其中包含一个箭头和一个描述该箭头的字符串。如果我使用函数(而不是箭头)执行此操作,则以下内容将按预期工作:
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)
为什么我会收到此错误,我应该怎么做才能避免它?
我们来看看
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)
可以是 any 数字类型的元组,并且类型检查器无法确定是哪一个,所以它是不明确的。这里的技巧是,我们将启用 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))
default
关键字可以帮助您。
我尝试编译这个:
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)'
所以,我的猜测是您需要决定要使用哪个箭头实例。 IE。您可能需要使用注释指定
arr funTimes
的具体类型。