4

アプローチではSum of Products、レコード機能をどのように取得しますか? レコードのデータ型 ( ) を使用した以下のコード例ghc 7.10.3:

{-# LANGUAGE DeriveGeneric #-}
import qualified GHC.Generics as GHC
import Generics.SOP
data Rec = Rec { frec :: Int, srec :: Maybe String}
  deriving (Show, GHC.Generic)

instance Generic Rec     -- empty
instance HasDatatypeInfo Rec

DataTypeInfo ghci プロンプトで見てみましょう:

*Main> datatypeInfo (Proxy :: Proxy Rec)
ADT "Main" "Rec" (Record "Rec" (FieldInfo "frec" :* (FieldInfo "srec" :* Nil)) :* Nil)

とはどちらもfrecas文字列を取るコンストラクタを持つ型です。したがって、実際の関数とを取得する方法がわかりません。show exampleも見ましたが、レコード機能は使用していません。srecFieldInfoFieldInfofieldNamefrec :: Rec -> Intsrec :: Rec -> Maybe String

レコード関数を取得する方法についてのポインタを高く評価します (型の HList である可能性がありますHList '[(Rec -> Int), (Rec -> Maybe String)]))。

質問への補遺

user2407038 がレイアウトしたアプローチを使用して、プロジェクションから関数を取得する方法について、タイプ ノットに縛られています。SOPしたがって、さらに質問に追加したいと思います: コンストラクターのアプローチを使用して、以下のような関数を構築するにはどうすればよいですか?Recここでは、レコード フィールド名と関数の両方を使用します。

[ ("frec" ++) . show . frec, ("srec" ++) . show . srec] 
4

1 に答える 1

5

ライブラリは、積の合計を操作するためのgenerics-sop一般的なコンビネータを実装しているため、これらのコンビネータを使用してそのような関数を作成する必要があります。

1 つの問題があります -generics-sop型レベルでのレコード対コンストラクターに関する情報がないため、関数はまだ部分的です (GHC ジェネリックを掘り下げない限りRep)。

この例では、部分関数ルートを使用します。

まず、次のデータ型が必要です。

data (:*:) f g x = f x :*: g x deriving (Show, Eq, Ord, Functor) 

ライブラリに含める必要があるようですが、そうではありません (または見つかりません)。

関数の型は

recordSelectors :: forall t r . (Code t ~ '[ r ], Generic t, HasDatatypeInfo t) 
                => Proxy t -> Maybe (NP (FieldInfo :*: (->) t) r)

この制約Code t ~ '[ r ]は、 のプロダクション表現の合計がtシングルトン リスト (1 つのコンストラクター) であることを単純に示しています。戻り値の型は (おそらく) リストr(レコード フィールドの型のリスト) の積であり、の各型には aFieldInfo xと aがあります。t -> xxr

1つの実装は

  case datatypeInfo (Proxy :: Proxy t) of 
    ADT _ _ (Record _ fields :* Nil) -> Just $ 
      hzipWith (\nm (Fn prj) -> nm :*: (unI . prj . K . (\(Z x) -> x) . unSOP . from)) 
               fields 
               projections 
    _ -> Nothing 

ここで関数は、指定されたデータ型が実際にはレコードであると判断し、それ以外の場合は を返しますNothing。レコードの場合は、レコード フィールドとprojections(ライブラリで定義された) をまとめて圧縮します。これは、任意の一般的な製品のプロジェクションを定義NP '[ Code Rec -> Int, Code Rec -> Maybe String ]します。残っているのはfrom、「実際の」投影を取得するために各投影で関数を構成することだけです。残り ( FnunSOPなど) は単なる ID です。


必要なのはレコード プロジェクション関数だけであり、関数名は不要であることが判明したため、これはさらに簡単です。そして今、関数は部分的ではありません.1つのコンストラクタータイプには「レコードプロジェクション」があります.

recordSelectors' :: forall t r . (Code t ~ '[ r ], Generic t) 
                 => Proxy t -> NP ((->) t) r
recordSelectors' _ = hmap (\(Fn prj) -> unI . prj . K . (\(Z x) -> x) . unSOP . from) 
                          projections 
于 2016-03-28T02:24:08.113 に答える