2012-02-27 52 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