2011-09-09 44 views
0

人們可以把這種情況下的如下曖昧類型變量'A1' : 應用程序動態加載模塊,或存在的用戶從中選擇的功能列表,等等。我們有一個機制來確定某個類型是否可以成功地在該模塊中使用一個函數。所以現在我們要調用這個函數。我們需要強制它打電話。該函數可以採用具體類型,也可以採用多態類型,下面只是一個類型約束,我遇到了問題。如何解決這個編譯錯誤:在約束

下面的代碼會導致以下錯誤。我認爲可以通過指定具體類型來解決,但我不想這樣做。該代碼旨在與任何類型的實例一起工作。指定具體類型會破壞目的。

這是模擬程序,不知道其他,不知道是什麼類型它處理的一個組成部分。我有一個單獨的機制,可以確保類型能夠正確匹配,確實發送的值是類型類的一個實例。這就是爲什麼在這種情況下,我不介意使用unsafeCoerce。但基本上我需要一種方法告訴編譯器,我確實知道它是可以的,無論如何,儘管它不知道鍵入check。

{-# LANGUAGE ExistentialQuantification, RankNTypes, TypeSynonymInstances #-} 
module Main where 

import Unsafe.Coerce 

main = do 
    --doTest1 $ Hider "blue" 
    doTest2 $ Hider "blue" 

doTest1 :: Hider -> IO() 
doTest1 [email protected](Hider h) = 
    test $ unsafeCoerce h 

doTest2 :: Hider -> IO() 
doTest2 [email protected](Hider h) = 
    test2 hh 

test :: HasString a => a -> IO() 
test x = print $ toString x 

test2 :: Hider -> IO() 
test2 (Hider x) = print $ toString (unsafeCoerce x) 

data Hider = forall a. Hider a 

class HasString a where 
    toString :: a -> String 

instance HasString String where 
    toString = id 

運行doTest1

[1 of 1] Compiling Main    (Test.hs, Test.o) 

Test.hs:12:3: 
    Ambiguous type variable `a1' in the constraint: 
     (HasString a1) arising from a use of `test' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: test 
    In the expression: test $ unsafeCoerce h 
    In an equation for `doTest1': 
     doTest1 [email protected](Hider h) = test $ unsafeCoerce h 

運行doTest2

[1 of 1] Compiling Main    (Test.hs, Test.o) 

Test.hs:12:3: 
    Ambiguous type variable `a1' in the constraint: 
     (HasString a1) arising from a use of `test' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: test 
    In the expression: test $ unsafeCoerce h 
    In an equation for `doTest1': 
     doTest1 [email protected](Hider h) = test $ unsafeCoerce h 
+0

看來答案是:你不能。因此,我將開始一個新的問題,詢問如何去做我想做的事情,並希望有一些方法可以做到與我所採取的方法不同。 – mentics

回答

2

I think it could be resolved by specifying concrete types but I do not want to do that.

有沒有辦法解決它雖與unsafeCoerce。在這種特殊情況下,編譯器無法推斷出unsafeCoerce的類型,因爲test仍然是多態的。即使只有一個HasString的實例,類型系統也不會使用該事實來推斷類型。

我沒有對這種模式的特定應用程序的足夠信息,但我比較肯定的,你需要重新考慮你在程序中使用的類型系統的方式。但是,如果您確實想要這樣做,您可能需要查看Data.Typeable而不是unsafeCoerce

+0

在實際情況下,不一定只有HasString的一個實例。我不明白你在用Data.Typeable建議什麼。 – mentics

+0

那麼,理論上不可能簡單地將'unsafeCoerce h'的類型推斷爲具體的東西,對吧? ;)關於'Data.Typeable':我從來沒有用過它,但我明白它可以幫助動態投射,這似乎是你想要做的。 – 2011-09-09 14:51:35

+0

唉,對不起; 'Data.Dynamic'不會動態輸入,它使用Typeable來完成。你可能想要閱讀它:) – 2011-09-09 15:04:48

1

稍微修改您的數據類型:

data Hider = forall a. HasString a => Hider a 

使其在明顯的方式的類型類的實例:

instance HasString Hider where 
    toString (Hider x) = toString x 

那麼這應該工作,不使用unsafeCoerce

doTest3 :: Hider -> IO() 
doTest3 hh = print $ toString hh 

這並不意味着你不能把一個值轉換爲Hider如果它不執行HasString,但這可能是一件好事。

有可能就是這個模式的名字,但我不認爲這是把我的頭頂部的東西。

+0

對不起,這對我不起作用。這是一個過於簡單化的例子。在完整的一個,任何可能放在Hider。 – mentics

+1

@taotree但是你試圖將一個非HasString類型強制爲一個HasString類型 - 這將不可避免地導致Haskell設計要避免的問題(比如段錯誤)。 「不安全的承諾」中的「不安全」真的代表「不使用這種證明是不安全的」,並且你說有證據表明它不安全。不要這樣做。 –

+0

我在哪裏說我有證明它不安全?我以爲我說我證明它是安全的。 – mentics