タイプのリスト(例えば'[Int, Int]
)を型とその型を作成するための方法の両方に解体しようとしています(ネストされたタプルと同形ですが、より良い書き込みをする)。例:タイプレベルリストを '[]のためのセンチネルのないネストされたタプルに分解する
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeFamilies, FlexibleInstances #-}
import Data.Kind (Type)
data a :<> b = a :<> b
infixr 8 :<>
class Construct a where
type Result a :: Type
instance forall a as. (Show a, Construct as) => Construct (a:as) where
type Result (a:as) = a :<> (Result as)
instance Construct '[] where
type Result '[] =()
これを使用すると、
λ :kind! Result '[Int, Int, Int]
Result '[Int, Int, Int] :: *
= Int :<> (Int :<> (Int :<>()))
最後に私がしたくないのは:<>()
です。最初はリストエレメントの長さに合わせてより具体的にマッチングを試みました。 「[A、B]:
instance forall a b. (Show a, Show b) => Construct ('[a,b]) where
type Result '[a,b] = a :<> b
しかし、動作しませんもちろん:
Conflicting family instance declarations:
Result (a : as) = a :<> Result as -- Defined at test.hs:14:8
Result '[a, b] = a :<> b -- Defined at test.hs:22:8
私は常にN特定のインスタンスまで構築することができます。
instance forall a. (Show a) => Construct '[a] where
type Result '[a] = a
instance forall a b. (Show a, Show b) => Construct '[a,b] where
type Result '[a, b] = a :<> b
instance forall a b c. (Show a, Show b, Show c) => Construct '[a,b,c] where
type Result '[a, b, c] = a :<> b :<> c
-- etc. up to N
しかし、それはそうです非常に満足していない。
再帰的定義を使用してInt :<> (Int :<> (Int :<>())))
の代わりにInt :<> (Int :<> Int)
に解凍する方法はありますか?
ありがとうございます!型クラスの閉じた型ファミリに相当することを知っていますか?私。 'handler :: Result a - > Text'のようなマッチング関数を書こうとすると、私は同じアンパックセンチネルの問題を抱えているようで、型クラスに移ったようです。 – teh
@teh私はあなたがしたいと思うもののために、より良い解決策になるべきものを編集してください。 –