Haskell Arrows里面的元组

时间:2012-02-27 13:33:00

标签: haskell functional-programming tuples arrows

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

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)

为什么我会收到此错误,我该怎么办,以避免它?

2 个答案:

答案 0 :(得分:9)

让我们看一下snd的类型:

snd :: (foo, x) -> x

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

类型指出,对于类型为foox的元组,返回x类型的内容。这里要知道的重要事情是,虽然价值体系又名。 Haskell中的运行时是懒惰的,Haskell的类型系统是严格的,这意味着在foo被调用之前必须知道xsnd的类型。

在第一种情况下,如果您只有Num b => (b -> b, String),则调用snd会使b不明确,因为您没有在任何地方提及其具体类型,而且它不能从返回类型推断,因为foo ~ bx不同。换句话说:因为(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