Haskell 如何在ADT';s构造函数';谁的论点?
我有一个数据类型(如下GADT格式所示): 我想做的是,能够将一些函数Haskell 如何在ADT';s构造函数';谁的论点?,haskell,Haskell,我有一个数据类型(如下GADT格式所示): 我想做的是,能够将一些函数monoidm=>testa->m一般地应用于构造函数中testa的任何给定实例,然后mappend全部应用 例如,给定f: f :: Test a -> [Int] f (C1 n _) = [n] f _ = [] 我想要一个函数g,它可以映射每个构造函数参数,如下所示: g :: Monoid m => (Test a -> m) -> Test a -> m g f v@(
monoidm=>testa->m
一般地应用于构造函数中testa
的任何给定实例,然后mappend
全部应用
例如,给定f:
f :: Test a -> [Int]
f (C1 n _) = [n]
f _ = []
我想要一个函数g,它可以映射每个构造函数参数,如下所示:
g :: Monoid m => (Test a -> m) -> Test a -> m
g f v@(C1 Int _) = f v
g f (C2 x y _) = f x `mappend` f y
g f (C3 x _) = f x
...
除了我不想写g
,我想写一个g
的泛型版本,它可以对任何支持的数据类型执行此操作(我认为GHC.Generics可能很适合此操作,但无法正确获取类型)。
i、 e.我想将遍历我的数据结构的实际机制(使用基于mappend
的折叠重复应用f
)与感兴趣的位(上面g
中的C1
的终端情况)分开
有什么想法吗?实际上,我会更深入地研究GHC.Generics,如果你没有的话,一定会阅读 我将在这里概述另一种方法,即使用不动点类型,它非常适合这个问题
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
实际上,我并没有从固定点类型中得到太多的使用,它们似乎总是比它们的价值更麻烦。但是现在实现了
模式同义词
,我认为这会更好一些。无论如何,我只是想向您展示这一点供您考虑。看起来您想要做的或多或少就是本文(第3节)中所述的函数组合的功能
该包裹声称有一个
对应于您似乎正在寻找的操作。是否应该仅将f
应用于使用C1
构造函数生成的值?为什么不是C2
或C3
构造函数?它只适用于没有递归参数的构造函数吗?如果有一个C4 Int(testa)
构造函数或C5 Int
构造函数,会发生什么?不,f
可以选择它想要的测试a
部分,因此根据问题中给出的f
的定义,我希望g
为C4 I r
和返回fr
(或记忆)对于C5 i
。希望这能澄清问题。你的评论实际上让我意识到f
调用函数进行折叠可能比使用g
调用f
更容易。GHC。泛型是一个很好的选择,如果你以前从未使用过它,它可能很难使用。你读过吗?--当我读这篇文章的时候不再是一个黑暗的咒语,开始成为一个有用的工具,想象一下!
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
composOpMonoid :: (Uniplate a, Monoid m) => (a -> m) -> a -> m