2012-02-27 69 views
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) 

为什么我得到这个错误,而我应该怎么做,才能避免呢?

回答

9

让我们来看看在snd类型:

snd :: (foo, x) -> x 

(我改名为清晰起见,类型变量)

什么类型的状态是与类型foox元组,返回的东西键入x。这里需要了解的重要一点是价值体系。 Haskell中的运行时是懒惰的,Haskell的类型系统是严格的,这意味着foox的类型都必须在调用snd之前知道。

在第一种情况下,当你只是有一个Num b => (b -> b, String),呼吁snd将离开b暧昧,因为你没有在任何地方提到其具体类型,它不能从返回类型推断,因为foo ~ b这是不同的从x。换句话说:因为(b, b)可以是的任何数字类型的元组,并且类型检查器无法弄清楚哪一个是模糊的。这里的诀窍是我们将拥有Haskell的违约规则,其中规定如果数字类型不明确,则默认为Integer。如果您以-Wall转而发出警告,则会说已发生这种情况。所以,我们的类型变为(Integer -> Integer, String)snd可以被调用。

但是,在第二种情况下,我们仍然设法通过违约规则推断出b,但a没有默认Arrow,所以我们被卡住了!您必须明确指定您想要继续的箭头!您可以通过首先使用的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可以帮助你。

+0

就是这样;)thx – frosch03 2012-02-27 14:07:02

+1

有多刺激。人们会期望类型系统能够得出结论:'snd aTuple10'的类型是'String';这可以被视为实施中的错误吗?当然,Haskell 2010没有指定这样的行为。有人可能会争辩说,如果实现不知道第一个东西是什么类型的,它不会知道第二个东西在内存中的什么位置,但是因为我们在这里处理盒装元组,所以应该总是有两个指针,因此无论第一个元素的类型如何,第二个元素都可以轻松定位。 – 2012-02-27 21:41:57

+2

像'class Boolish a where toBool :: a - > Bool; foo :: Boolish a =>(a,b) - > b; foo(a,b)=如果toBool a然后b else undefined'是可以想象的,所以函数的结果可以依赖于一个模棱两可的参数。在这种情况下,'snd'的特殊外壳会很奇怪。 – dflemstr 2012-02-27 21:54:59

-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的具体类型。

+0

这里的错误与手头的问题完全无关。这似乎是因为你忘记了'funTimes10'的类型签名。查看[Monomorphism Restriction](http://www.haskell.org/haskellwiki/Monomorphism_restriction)。 – dflemstr 2012-02-27 14:06:57

+0

@dflemstr我的答案是否显示原始问题? **我**没有忘记签名,原始帖子中没有。虽然我没有描述潜在的问题(因为我没有看到它),但我认为这不值得我的答案下调。 – Andre 2012-02-27 16:00:06

+1

我认为OP只是复制了他的函数的定义来演示他正在使用哪种类型的值。他有一个多态的'funTimes10',否则他会得到一个不同的错误。 – dflemstr 2012-02-27 16:44:13