私は-XDataKinds
最近遊んでいて、型ファミリを使用して昇格された構造ビルドを取得し、それを値レベルに引き下げたいと考えています。これが可能なのは、構成要素が非常に単純であり、端末の表現が単純であるからだと思います。
バックグラウンド
Strings
種類の型になるの単純なバラの木を降格/反映したいと思います(型レベルの文字列としてTree Symbol
使用する場合)。GHC.TypeLits.Symbol
ここに私のボイラープレートコードがあります:
{-# LANGUAGE DataKinds #-}
import GHC.TypeLits
import Data.Proxy
data Tree a = Node a [Tree a]
type TestInput = '[ 'Node "foo" '[ 'Node "bar" '[]
, 'Node "baz" '[]
]
, 'Node "bar" '[]
]
これは、次の非常に詳細な図のように見える単純な型レベルのバラの森です。
*-- "foo" -- "bar"
| \_ "baz"
\_ "bar"
試みられた解決策
理想的には、この構造をトラバースして、 kind の値*
に 1 対 1 のマッピングを返したいのですが、過負荷のために (必要な) インスタンスを持ち越しながら、これを異種混合で行う方法はあまり明白ではありません。
vanila on#haskell
は、型クラスを使用して 2 つの世界をバインドすることを提案しましたが、思ったよりもややこしいようです。私の最初の試みは、インスタンス ヘッドの制約を介して型レベルのパターン マッチの内容をエンコードしようとしましたが、関連付けられた型 (*
マッピングの -kinded 型の結果をエンコードするため) がオーバーラップしました。明らかに、インスタンス ヘッドは GHC によって多少無視されます。
理想的には、リストとツリーのリフレクションもジェネリックにすることを望みますが、これは問題を引き起こしているようです。これは、型クラスを使用して型/種類の層を整理するようなものです。
これは私が望むものの非機能的な例です:
class Reflect (a :: k) where
type Result :: *
reflect :: Proxy a -> Result
class ReflectEmpty (empty :: [k]) where
reflectEmpty :: forall q. Proxy empty -> [q]
reflectEmpty _ = []
instance ReflectEmpty '[] where
instance ReflectEmpty a => Reflect a where
type Result = forall q. [q]
reflect = reflectEmpty
-- | The superclass constraint is where we get compositional
class Reflect (x :: k) => ReflectCons (cons :: [x]) where
reflectCons :: PostReflection x ~ c => Proxy cons -> [c]
instance ( Reflect x
, ReflectCons xs ) => ReflectCons (x ': xs) where
reflectCons _ = reflect (Proxy :: Proxy x) :
reflectCons (Proxy :: Proxy xs)
instance ( Reflect x
, ReflectEmpty e ) => ReflectCons (x ': e) where
reflectCons _ = reflect (Proxy :: Proxy x) :
reflectEmpty (Proxy :: Proxy e)
...
このコードには一般的に間違っている点がいくつかあります。ここに私が見るものがあります:
PostReflection
ジェネリック型レベルのリスト リフレクション -型関数の高次リフレクションの結果を知るには、何らかの形式の先読みが必要です。- その場で を作成および破棄する必要があります
Proxy
。これが現在コンパイルされないかどうかはわかりませんが、期待どおりに型が統合されるかどうかはわかりません.
しかし、この型クラスの階層構造は異種文法を捉える唯一の方法のように感じられるので、これはまだ出発点かもしれません。これに関するどんな助けも途方もないでしょう!