2016-05-31 70 views
2

說,比如我有一個類型的類,例如,對於每一個實例的這種類型的類我有一個函數如何指定從中調用函數

f :: [Bool] -> Maybe (a, [a]) 

我怎樣才能調用F?更確切地說,如果b是另一個在此類型中的類型,我怎麼能指定我是從a的實例開始的而不是從b的實例開始的?

回答

7

有時您必須添加類型註釋。考慮類型類Read

class Read a where 
    read :: String -> a 

如果您嘗試read "1"期望得到的整數1,你會得到一個錯誤,而不是因爲沒有辦法知道什麼類型a是。但是,這工作:read "1" :: Int

如果你正在使用你的函數f在編譯器可以找出什麼a的情況下,那麼它會正常工作。否則,您必須通過添加適當的類型註釋來幫助編譯器。

3

typeclass實例通過聲明它們的特定類型進行索引。例如,在以下情況下:

class YourClass a where 
    f :: [Bool] -> Maybe (a, [a]) 

instance YourClass Int where 
    f = error "Define me" 

instance YourClass Char where 
    f = error "Define me" 

YourClass兩個獨特的情況。當aInt時,另一個 - 當它是Char。這些實例使用f函數實際應用的類型自動解析。

因此,只要您使用f就好像它具有特定簽名[Bool] -> Maybe (Int, [Int])一樣,Int的實例會自動拾取。由於Haskell也有非常強大的類型推斷,所以在大多數情況下並不需要指定這個特定的簽名,編譯器會自動從上下文中解析它。

所以基本上,你可以簡單地在你有實例的所有類型上使用該函數,並且安全地期望編譯器爲你完成剩下的工作。

+0

嗯,'Num','Read','Show' ... – dfeuer

+1

好了,但還有的arent情況時,這是曖昧?例如,在我的具體情況下,我想在這樣的case表達式中使用f:case f xs Nothing - > something ...只是(a,as) - >別的東西... Haskell如何知道我是哪個使用? – user3726947

+1

@ user3726947如果你有這個表達式的函數不關心哪個特定類型爲「a」,那麼它是一個多態函數,並且將具有像'f2 ::(YourClass a)=> a - > ...' –

3

爲了補充其他答案,我會指出確實有些情況可能是不明確的。

例如:

class C a where 
    f :: String -> a 
instance C Int where 
    f s = length s 
instance C Bool where 
    f s = s == "hello!" 

main :: IO() 
main = print (f "testing") 

現在,print接受任何(Show能)類型,並且f "testing"能產生兩者IntBool。由於上面的程序可能會打印出「False」以及「7」,所以這本質上是不明確的。編譯器無法解決這個問題。

作爲一個解決方案,我們可以使用

main = print (f "testing" :: Int) 
-- or 
main = print (f "testing" :: Bool) 

消除歧義。另一個不太方便的選項是

main = print ((f :: String -> Int) "testing") 

甚至在GHC 8。0,右邊的分機上,

main = print (f @ Int "testing") -- explicit choice for type a 

但請注意,在某些情況下,沒有歧義,GHC可以創造奇蹟。例如:

main = print (f "testing" && True)   -- Bool is chosen here 
main = print (f "testing" + length [1,2]) -- Int is chosen here 

這是因爲&&需要Boollength回報Int+迫使兩個參數具有相同類型的(所以f "testing"必須Int以及)。

也正在

bar :: Bool -> Float 
bar b = ... 

main = print (bar (f "testing)) -- Bool is chosen 
相關問題