2016-12-20 4 views
3

私は(GADT形式で、以下に示す)のデータ型があります:私は何をしたいかADTのコンストラクタの引数をマップする方法は?

data Test a where 
    C1 :: Int -> a -> Test a 
    C2 :: Test a -> Test a -> a -> Test a 
    C3 :: Test a -> a -> Test a 
    ... 

は、その後、コンストラクタでTest aの任意のインスタンスに一般的にいくつかの機能Monoid m => Test a -> mを適用することができることですmappendそれをすべて。

したがって、たとえば、F与えられた:私はしたくないことを除いて

g :: Monoid m => (Test a -> m) -> Test a -> m 
g f [email protected](C1 Int _) = f v 
g f (C2 x y _) = f x `mappend` f y 
g f (C3 x _)  = f x 
... 

f :: Test a -> [Int] 
f (C1 n _) = [n] 
f _  = [] 

私はそうのような各コンストラクタの引数の上にこれをマッピングすることができ、いくつかの関数gを希望gを書くには、サポートされているデータ型に対してこれを行うことができるgのジェネリック版を書いてみたい(GHC.Genericsはこれに適していると思っているが、タイプを正しく取得できなかった)。すなわち 私は面白いビットから自分のデータ構造(mappendベース倍とfの繰り返しアプリケーション)を横断する実際の仕組み(上記gC1の端子ケース)

任意のアイデアを分離したいのですが?

+3

'C1'コンストラクタで作られた値だけに' f'を適用することになっていますか?なぜ、「C2」または「C3」コンストラクタではありませんか?それは再帰的引数を持たないコンストラクタのためだけですか? 'C4 Int(Test a)'コンストラクタまたは 'C5 Int'コンストラクタがあった場合、どうなりますか? –

+0

いいえ、 'f'は' Test a'パーツを選ぶことができるので、 'f'の定義が与えられているので、' g'は 'C4 ir'と' ] ''(またはmempty)を返します。あなたのコメントは、 'f'が' f'を 'f'を呼び出すよりも簡単に関数を呼び出す方が簡単かもしれないことを実際に気付かせました。 – Chetan

+0

GHC.Genericsは良い賭けです。これまで使ったことがない人は、使いにくいかもしれません。 [the the paper](https://www.microsoft.com/en-us/research/wp-content/uploads/2003/01/hmap.pdf)を読んだことがありますか? - 私が紙を読んだとき、それは暗い呪文ではなくなり、有用な道具になり始めました、それを想像してください! – luqui

答えて

1

実際に、私はGHC.Genericsに少し深く見て、間違いなくあなたがいない場合the SYB paperを読みました。

私はこの問題のためにかなり滑らかなフィット感である不動点タイプを使用することです、ここで別のアプローチを概説します。

newtype Mu f = Roll { unroll :: f (Mu f) } 

-- Replace all recursive constructors with r. 
-- If any of them are nonregular (e.g. C3 :: Test Int -> Test a) 
-- then this approach gets quite a bit more complicated, so I hope not. 
data TestF a r where 
    C1 :: Int -> a -> TestF a r 
    C2 :: r -> r -> a -> TestF a r 
    ... 

-- This will take care of finding the recursive constructors 
deriving instance Foldable (TestF a) 

-- This is your actual type (might want to wrap it in a newtype) 
type Test a = Mu (TestF a) 

foldMapRec :: (Foldable f, Monoid m) => (Mu f -> m) -> Mu f -> m 
foldMapRec f (Roll a) = foldMap f a 

実際には、実際には固定小数点タイプを使い果たしていませんが、常に価値があるよりも面倒です。しかし、PatternSynonymsが実装されたことで、やや良いと思います。とにかく、ちょうどあなたの配慮のためにこれを表示したい。

0

あなたがしたいように見えるのは、composFoldの機能が、"A pattern for almost compositional functions"(セクション3)に記載されているように機能しているように見えます。

uniplateパッケージは

composOpMonoid :: (Uniplate a, Monoid m) => (a -> m) -> a -> m 

は、あなたが探しているように見える操作に対応して、compatibility layer for compos-like operationsを持っていると主張しています。

関連する問題