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