9

私が DSL を書いていて、ファントム型のサポートと正しく型付けされていない式の両方をサポートしたいとしましょう。私の値のタイプは

{-# LANGUAGE GADTs, DataKinds #-}

data Ty = Num | Bool deriving (Typeable)

data Val a where
  VNum  :: Int  -> Val Num
  VBool :: Bool -> Val Bool

ファントム消去バージョンで作業できます

{-# LANGUAGE ExistentialQuantification #-}

data Valunk = forall a . Valunk (V' a)

これで、この方法でファントム タイプの両方を削除したり、再構築したりValunkすることで、 の値を操作できます。caseVNumVBool

getNum :: Valunk -> Maybe (Val Num)
getNum (Valunk n@(VNum _)) = Just n
getNum _                   = Nothing

Typeableしかし、これは機械を再実装しているように感じます。Typeable残念ながら、GHC ではfor を導出できません。Val

src/Types/Core.hs:97:13:
    Can't make a derived instance of `Typeable (Val a)':
      Val must only have arguments of kind `*'
    In the data declaration for Val

この制限を回避する方法はありますか? ぜひ書きたい

getIt :: Typeable a => Valunk -> Maybe (Val a)
getIt (Valunk v) = cast v

しかし今、私はこのような機械に頼らなければなりません

class Typeably b x where kast :: x a -> Maybe (x b)
instance Typeably Num Val where 
  kast n@(VNum _) = Just n
  kast _          = Nothing

私のすべてのタイプに。

4

2 に答える 2

1

自分で Data.Typeable を派生させることができます。

{-# LANGUAGE GADTs, DataKinds, DeriveDataTypeable, ExistentialQuantification #-}

import Data.Typeable

data Ty = TNum | TBool deriving Typeable 

data Valunk = forall a. Typeable a => Valunk a 

data Val a where 
    VInt :: Int -> Val TNum
    VBool :: Bool -> Val TBool 

instance Show (Val a) where 
    show (VInt a) = show a
    show (VBool a) = show a 

valtypenam = mkTyCon3 "package" "module" "Val"

instance Typeable (Val a) where 
    typeOf _ = mkTyConApp valtypenam []

getIt :: Valunk -> Maybe (Val a)
getIt (Valunk p) = cast p 

これにより、get it 機能が提供されます。タイプに正しい名前を付けてください (したがって、パッケージ、モジュール、およびタイプを正直にファイルしてください)。そうしないと、他のパッケージが問題を起こす可能性があります。

これらのインスタンスを記述する方法のその他の例については、Data.Derive.Typeable sourceを参照してください。

編集: コードに非常に奇妙なコピーと過去のエラーがありましたが、現在は機能しています。

于 2013-08-11T21:28:57.857 に答える
1

まず、数量化された型 inValunkが inであるという証人を保存する必要がありTypeableます。

data Valunk = forall a . Typeable a => Valunk (Val a)

gcastこれを取得したら、求めていることを達成するために使用できます。

getIt :: Typeable a => Valunk -> Maybe (Val a)
getIt (Valunk v) = gcast v

これは以下でテストされました:

data Val a where
  VNum  :: Int  -> Val Int
  VBool :: Bool -> Val Bool
于 2013-08-15T05:32:38.483 に答える