Haskell记录的Monoid、Applicative、Monad等字段分布

3
有没有一个包能够大致完成以下功能:
给定一条记录:
data R = R { a :: TypeA,
             b :: TypeB,
             c :: TypeC }

生成一个提升的记录:

data R_L f = R_L { a_L :: f TypeA,
                   b_L :: f TypeB,
                   c_L :: f TypeC }

并提供了一些类似于以下示例和函数的功能:

instance (Monoid (f TypeA), Monoid (f TypeB), Monoid (f TypeC))
         => (Monoid (R_L f)) where
  mempty = R_L mempty mempty mempty
  mplus a b = ...fieldwise mplus...

sequenceR :: (Monad m) => R_L m -> m R
sequenceR = ... run fields, sum results ...
sequenceRA :: (Applicative m) => R_L m -> m R
sequenceRA x = R <$> a_L x <*> b_L x <*> c_L x

还有其他的库可以提供这种功能吗?如果没有,使用哪种机制(TH?Generics?)来实现最好?


那个幺半群实例没有意义,因为 f 的种类是 * -> *。可以使用 MonadPlus,这是你的意思吗? - leftaroundabout
已编辑以使Monoid实例稍微更清晰,但我也欢迎MonadPlus实例。 - Gracjan Polak
2个回答

4

使用generic-deriving可以实现单子部分,它提供了一种替代的GMonoid,其中泛型自动成为一个实例。

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances, FlexibleContexts, DefaultSignatures #-}

import Data.Monoid
import qualified Generics.Deriving.Monoid as M

data R_L f = R_L { a :: f [()],
                   b :: f String,
                   c :: f () } deriving (Generic)

现在你可以做以下事情:
*Main> let x = R_L (Just [()]) Nothing (Just ()) `M.gmappenddefault` R_L (Just [()]) (Just "foo") (Just ())
*Main> a x
Just [(),()]
*Main> b x
Just "foo"
*Main> c x
Just ()

我还在研究通用的 Show 实例。
可以按照以下方式创建普通的 Monoid 实例(虽然这可能又被称为样板代码...):
instance (Monoid (f [()]), Monoid (f String), Monoid (f ())) => Monoid (R_L f) where
    mempty = M.memptydefault
    mappend = M.mappenddefault

在这个包中,还有其他派生实例,用于FunctorTraversableFoldable
如果你改变类型的种类,MonadApplicative也许可以像现有实例一样使用泛型进行建模;尽管可能不是你所期望的方式,因为我认为它们只有作为字段类型的乘积函子才有意义,而不是你所提出的方式。

1
谢谢您提供的通用派生提示,这对我很有用。不过请注意,您的建议并没有从R中派生出R_L,因此对我来说只是部分解决方案。 - Gracjan Polak
哦,抱歉,我误解/忽略了您对_deriving_的使用。我仍然会保留答案,因为您发现它有用。 - phipsgabler

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接