2013-08-20 169 views
0

我要覆蓋的動態數據類型等類以這樣的方式訪問構造函數名和參數

instance Eq Dynamic where 
    x==y = dynamicEq x y 
dynamicEq :: Dynamic -> Dynamic -> Bool 
dynamicEq x y = ConstrName x == ConstrName y && sameSlots(slots x)(slots y) 
    where 
    sameSlots [] [] = True 
    sameSlots ((x::Eq a => a):xs)(y:ys) = x == fromDynamic y && sameSlots xs ys 

您可以命名或聲明可返回值的任何功能ConstrName插槽對我來說?也許使用Tycon或類似的東西?

+0

我認爲爲Dynamic創建一個'Eq'實例是不可能的。爲了比較兩個對象,如果你知道類型,你就完成了,如果沒有,就會遇到麻煩 - 你不能將值轉換回靜態世界,因爲你不知道要強制的類型,除非你賦予它一個單形類型(以及你可以如何創建一個動態的相等謂詞?),否則你不能創建'(==)''Dynamic'。 (請參閱[API](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Dynamic.html)。)除非這是一個實驗,否則可能有更好的方法來完成無論你想要做什麼。 – Fixnum

+0

你知道如何從靜態類型導出動態的Eq行爲嗎? – ye9ane

+0

我認爲'Data.Dynamic'的作者沒有提供這樣一個實例,這是你不能寫的:)的一個很好的理由。 – Fixnum

回答

1

從來沒有擺弄這個東西,但這裏可能有兩個部分的答案可能足夠你。恐怕這不是一個通用的解決方案,也不是一種製作DynamicEq實例的方法(如果它很簡單,它可能已經是一個了)。

但是在你上次的評論中,你表示你只是想比較自己的類型。所以,部分回答1:

如果你猜他們的類型,你當然可以比較兩個Dynamics。例如:

eqInt :: Int -> Int -> Bool 
eqInt = (==) 

x = toDyn (3::Int) 
y = toDyn (3::Int) 
z = toDyn (4::Int) 

compareDynamic :: (Typeable a, Eq a) => 
       (a -> a -> Bool) -> 
       Dynamic -> Dynamic -> Maybe Bool 
compareDynamic eq x y = do 
       let dEq = toDyn eq 
       fn1 <- dynApply dEq x 
       res <- dynApply fn1 y 
       fromDynamic res 

現在:

...> compareDynamic eqInt x y 
Just True 
...> compareDynamic eqInt x z 
Just False 

然而,儘管有誤導性的多態型的compareDynamic,你只能傳遞一個單態比較功能。請參閱:

...> compareDynamic (==) x z 
Nothing 

我想這是因爲該類型系統無法知道其中的(==)比如,它實際上應該在這裏使用的方式。我保持compareDynamic多態,但不必爲每種類型創建單獨的函數。

現在,因爲你只需要比較自己的類型,你可以只是比較功能的列表,你才能嘗試:

eqs = [eqMyTypeA, eqMyTypeB, eqMyTypeC] 
comp dynA dynB = catMaybes $ map (\eq -> eq dynA dynB) eqs 

而且[]將意味着兩種不同類型,[Just False]同一類型具有不同的值和[Just True]相同的類型和價值。

如果您有大量類型,您也可以在做比較之前確定構造函數(這是部分答案2),並根據它選擇正確的函數。它的構造函數是不同的,你根本不需要進行比較:

constructor :: Dynamic -> TyCon 
constructor = typeRepTyCon . dynTypeRep 

並且有一個匹配構造函數和相等函數的查找表。

一個結束語:如果你需要這個,請三思。想想三次,如果你需要Dynamic,大多數Haskell程序都不需要。是不是隻有Java思維偷偷摸摸?