0

我有一個數據類型,它帶有'隱藏'(推斷)類型和具體值。現在我嘗試實現一個可以改變這兩種功能的功能,但無法通過GHC。變換參數化類型(帶有推斷參數)

我的示例代碼是這樣的:

data T tag val = T val 

data A = A 
data B = B 

mkIntVal :: T a b -> T Int b 
mkIntVal (T x) = T x 

mkCharVal :: T a b -> T Char b 
mkCharVal (T x) = T x 

convert :: T Int a -> T Char b 
convert (T A) = mkCharVal $ T B 
convert (T B) = mkCharVal $ T A 

它產生的錯誤是這樣的:

test.hs:13:12: 
    Couldn't match type `A' with `B' 
    In the pattern: A 
    In the pattern: T A 
    In an equation for `convert': convert (T A) = mkCharVal $ T B 

test.hs:13:17: 
    Couldn't match type `B' with `A' 
    Expected type: T Char b 
     Actual type: T Char B 
    In the expression: mkCharVal $ T B 
    In an equation for `convert': convert (T A) = mkCharVal $ T B 

了什麼工作要做,以使這項工作?我必須更改數據結構嗎?


編輯

我試圖延長Don Stewart的解決方案與多態數據類型的工作。我一直在玩弄實例定義,但最有前途的期待與想出了是這樣的:

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE FlexibleContexts #-} 

data C a = C a deriving Show 

class Convertable inVal outVal outTag | outVal -> outTag where 
    convert :: T Int inVal -> T outTag outVal 

instance Convertable A B Char where 
    convert (T A) = mkCharVal $ T B 

instance Convertable B A Char where 
    convert (T B) = mkCharVal $ T A 

instance Convertable a b Char => Convertable (C a) (C (T Char b)) Char where 
    convert (T (C val)) = mkCharVal $ T (C (convert val)) -- line 29 

但是這給了我又一個錯誤信息:

test.hs:29:57: 
    Could not deduce (a ~ T Int inVal0) 
    from the context (Convertable a b Char) 
     bound by the instance declaration at test.hs:28:10-70 
     `a' is a rigid type variable bound by 
      the instance declaration at test.hs:28:22 
    In the first argument of `convert', namely `val' 
    In the first argument of `C', namely `(convert val)' 
    In the first argument of `T', namely `(C (convert val))' 

正如唐說,這應該是可能我對這將如何實施感興趣。


解決方案

多了很多「玩」後,我終於想出了一些作品。這對你看起來不錯嗎?

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 
{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE UndecidableInstances #-} 
{-# LANGUAGE OverlappingInstances #-} 


data T tag val = T val deriving Show 

data A = A deriving Show 
data B = B deriving Show 
data C a = C a deriving Show 


class Convertable inTag inVal outTag outVal | inTag -> outTag, inVal -> outVal 
where 
    convert :: T inTag inVal -> T outTag outVal 

instance Convertable Int A Char B where 
    convert (T A) = T B 

instance Convertable Int B Char A where 
    convert (T B) = T A 

instance (Convertable Int (T Int a) Char (T Char b), Convertable Int a Char b) 
    => Convertable Int (C (T Int a)) Char (C (T Char b)) where 
    convert (T (C x)) = T (C (convert x)) 

instance Convertable Int (C (T Int A)) Char (C (T Char B)) where 
    convert (T (C x)) = T (C (convert x)) 

instance Convertable Int (C (T Int B)) Char (C (T Char A)) where 
    convert (T (C x)) = T (C (convert x)) 

用法:

*Main> convert $ mkIntVal $ T $ C $ mkIntVal $ T A 
T (C (T B)) 
*Main> :t it 
it :: T Char (C (T Char B)) 

回答

1

convert功能的每個案例都有一個不同的,相互衝突的類型:

convertA :: T t A -> T Char B 
convertA (T A) = mkCharVal $ T B 

convertB :: T t B -> T Char A 
convertB (T B) = mkCharVal $ T A 

您可以通過一個類型類統一這些,

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FunctionalDependencies #-} 


class C a b c | b -> c where 
    convert :: T t a -> T c b 

instance C A B Char where 
    convert (T A) = mkCharVal (T B) 

instance C B A Char where 
    convert (T B) = mkCharVal (T A) 

如果你真的希望在不同類型的單一功能下,向不同的方向轉換。請注意,這是如何將帶有標籤的任何T放棄它,並用由值類型確定的新標籤替換標籤和值。

+0

現在我明白我的嘗試出了什麼問題。稍後有可能將此解決方案擴展爲多態結果類型,還是僅限於「正常」類型?因爲我沒有任何具體的值放入實例定義中,所以我不知道如何去執行像'convert(T(C val))= mkCharVal $ T(C(convert val))' – 2011-05-03 23:14:40

+0

應該是可以的。嘗試一下! – 2011-05-03 23:18:28