2017-06-20 83 views
3

我想在Haskell中創建一個函數,它根據給定的數據類型執行不同的操作。我認爲課堂應該做我想做的事,但現在我遇到了一個問題。我想能夠做的是類似於:在沒有聲明實例的情況下調用類中的函數

let x1 = myFunction :: MyInstance1 
let x2 = myFunction :: MyInstance2 

它根據給定的實例做不同的事情。

我目前的做法是

class MyClass a where 
    create :: Int -> a 
    doSomething :: a -> [Int] 

    myFunction :: [Int] 
    myFunction = doSomething $ create 4 

instance MyClass MyInstance1 where 
    -- implementation of create and doSomething 

instance MyClass MyInstance2 where 
    -- implementation of create and doSomething 

然而,編譯器告訴我「之類的變量A0是模糊支票‘myFunction的’曖昧」,從我一直在讀這是關係到編譯器不知道要調用什麼樣的'doSomething'實例。

那麼有沒有辦法以「通用」方式調用'doSomething'並稍後執行數據類型?或者我需要一個完全不同的方法來解決我的問題?

---編輯---

所以我申請的回答我的問題,但它並沒有解決它徹底呢。這裏是我的代碼

{-# LANGUAGE AllowAmbiguousTypes #-} 

class C a where 
    myFunction :: Int 
    create :: Int -> a 
    doSomething :: a -> Int 
    -- anotherFunction :: Int -> Int 
    -- anotherFunction x = doSomething $ create 4 

instance C Int where 
    myFunction = 1 
    create x = 2 * x 
    doSomething x = x + 4 

instance C Bool where 
    myFunction = 2 
    create x = True 
    doSomething x = if x then 42 else 24 

這編譯和我的提示

create @ Bool 4 
create @ Int 4 

返回預期的結果。然而,anotherFunction不正確編譯給出錯誤信息

Test.hs:8:23: error: 
    • Could not deduce (C a0) arising from a use of ‘doSomething’ 
     from the context: C a 
     bound by the class declaration for ‘C’ at Test.hs:(3,1)-(8,44) 
     The type variable ‘a0’ is ambiguous 
     These potential instances exist: 
     instance C Bool -- Defined at Test.hs:15:10 
     instance C Int -- Defined at Test.hs:10:10 
    • In the expression: doSomething $ create 4 
     In an equation for ‘anotherFunction’: 
      anotherFunction x = doSomething $ create 4 
Failed, modules loaded: none. 

是它根本不可能使用DoSomething的在這種情況下?我的想法是落實以同樣的方式作用於所有實例,然後寫

anotherFunction @ Bool 4 
anotherFunction @ Int 6 

回答

4

你需要一對夫婦的擴展,這樣做,但它是可行的。這裏展示的是一個GHCI會話:

> :set -XAllowAmbiguousTypes 
> class C a where myFunction :: Int 
> instance C Int where myFunction = 1 
> instance C Bool where myFunction = 2 
> :set -XTypeApplications 
> myFunction @ Int 
1 
> myFunction @ Bool 
2 

「舊」的解決辦法是添加一個代理參數

class C a where myFunction :: proxy a -> Int 

但希望這將淡出的風格在幾年 - 我發現經過類型明顯比傳遞代理更清晰。


的完整代碼,用另一個例子:

{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-} 

class C a where 
    myFunction :: Int 
    create :: Int -> a 
    doSomething :: a -> Int 
    anotherFunction :: Int -> Int 
    anotherFunction x = doSomething $ create @ a 4 

instance C Int where 
    myFunction = 1 
    create x = 2 * x 
    doSomething x = x + 4 

instance C Bool where 
    myFunction = 2 
    create x = True 
    doSomething x = if x then 42 else 24 

測試:

> :set -XTypeApplications 
> anotherFunction @ Bool 4 
42 
> anotherFunction @ Int 6 
12 
+0

編輯,以解決您的建議是什麼的問題。謝謝回答! – ryan91

+1

@ ryan91您需要爲此傳遞'a'類型,請參閱我的編輯。 – chi

+0

當然!我只是慢慢地找到你的解決方案,但還沒有完成,非常感謝! – ryan91

相關問題