2017-06-21 8 views
1

はこれです:拡張記録(と思う)私は大体欲しい

data A = ... 
data B = ... 
data C = ... 

class HasA t where 
    getA :: t -> A 

class HasB t where 
    getB :: t -> B 

class HasC t where 
    getC :: t -> C 

だから私は、この(擬似コードは、次の)ような何か行うことができます。当然のことながら

a :: A 
b :: B 

x = mkRecord { elemA a, elemB b } 
y = mkRecord { elemB b, elemA a } 

-- type of `x` == type of `y` 

を、唯一の適切なget機能が動作上記の場合、getAとです。

これはので、おそらくこのため、解像度が既に存在して新しい問題ではありませんように私はまた、次のような機能

slice :: Subset a b => a -> b 
slice x = -- just remove the bits of x that aren't in type b. 

add :: e -> a -> a ++ e 
add e x = -- add an element to the "record" (compile error if it's already there) 

のように私は感じると思います。私は、ソリューションが拡張可能である必要はないことに注意してください。対処する必要があるタイプの量は有限で既知ですが、もちろん拡張可能なものは傷つきません。

私が探している分野、つまりHListextensibleのようなパッケージがいくつか見つかりました(私のレコードを並べ替えたいので拡張性があるかもしれません)。 Hackageのドキュメントでは少し失われているので、私が探しているものをおおよそ実現するサンプルコード(またはサンプルコードへのリンク)がほしいと思います。

答えて

1

これはまさにHListが適しているものです。しかし、今すぐHListパッケージで何かをテストするための適切な設定がないので(more confusing data definitions)、singletonsという最小レベルの例がsingletonsで、タイプレベルのリストのものになります。

{-# LANGUAGE DataKinds, TypeOperators, GADTs,TypeFamilies, UndecidableInstances, 
    PolyKinds, FlexibleInstances, MultiParamTypeClasses 
    #-} 

import Data.Singletons 
import Data.Promotion.Prelude.List 

data HList (l :: [*]) where 
    HNil :: HList '[] 
    HCons :: x -> HList xs -> HList (x ': xs) 

add機能が最も簡単です:二つのレコードを結合され、より興味深い

add :: x -> HList xs -> HList (x ': xs) 
add = HCons 

何か:それはちょうどHConsあるごget機能のために、

-- Notice we are using `:++` from singletons 
combine :: HList xs -> HList ys -> HList (xs :++ ys) 
combine HNil xs = xs 
combine (x `HCons` xs) ys = x `HCons` (xs `combine` ys) 

さて、あなたが必要タイプレベルのリストに基づいてディスパッチする。これを行うには、オーバーラップする型クラスが必要です。

class Has x xs where 
    get :: xs -> x 

instance {-# OVERLAPS #-} Has x (HList (x ': xs)) where 
    get (x `HCons` _) = x 

instance Has x (HList xs) => Has x (HList (y ': xs)) where 
    get (_ `HCons` xs) = get xs 

最後に、我々は同様のSubsetクラスを定義するHasを使用することができます。以前と同じアイデア。


あなたは括弧で言及したよう

class Subset ys xs where 
    slice :: xs -> ys 

instance Subset (HList '[]) (HList xs) where 
    slice _ = HNil 

instance (Get y (HList xs), Subset (HList ys) (HList xs)) => 
      Subset (HList (y ': ys)) (HList xs) where 
    slice xs = get xs `HCons` slice xs 

、シンプルな HListフォームを使用すると、フィールドのいずれかのタイプの唯一持っていることを確認しません(そう getはちょうど残りを無視して、最初のフィールドを返します)。一意性が必要な場合は、コンストラクタ HListに制約を追加するだけです。

data Record (l :: [*]) where 
    Nil :: Record '[] 
    Cons :: (NotElem x xs ~ 'True) => x -> Record xs -> Record (x ': xs) 

しかし、それはいくつかの証明を必要とするようRecordに見える使用してSubsetを定義します。 :)

関連する問題