从 `mappend` 函数到 `Monoid` 实例的函数?

Function from `mappend` function to `Monoid` instance?

我有一个数据结构(它是rose-tree的一个特定子class,它形成了一个具有最大下限和最低上限函数的格子),它支持两个非常合理的函数来服务作为 Monoid class 的 mappend

有什么方法可以在 haskell 中支持匿名 Monoid 实例吗?这是我应该考虑使用诸如 Template-Haskell 之类的东西来为我生成类型 classes 的实例吗?

我想要的是 makeMonoid :: (RT a -> RT a -> RT a) -> Monoid a 让我即时创建实例,但我知道这与我理解的股票类型系统不一致。 如果我只需要选择一个默认合并函数并为其他合并编写 newtypes,我可以接受,只是好奇

可以使用存储库reflection package. There's a ready-made example中的工具即时创建Monoid的"local"个实例。这个答案稍微解释一下。

这是对 a 类型值的新类型包装器,我们将在其上定义我们的 Monoid 实例。

newtype M a s = M { runM :: a } deriving (Eq,Ord)

请注意,有一个幻影类型 s 没有出现在右侧。它将携带本地 Monoid 实例工作所需的额外信息。

这是一条记录,其字段代表Monoidclass的两个操作:

data Monoid_ a = Monoid_ { mappend_ :: a -> a -> a, mempty_ :: a }

以下是 MMonoid 实例定义:

instance Reifies s (Monoid_ a) => Monoid (M a s) where
    mappend a b        = M $ mappend_ (reflect a) (runM a) (runM b)
    mempty = a where a = M $ mempty_ (reflect a)

它说:"whenever s is a type-level representation of our Monoid dictionary Monoid_, we can reflect it back to obtain the dictionary, and use the fields to implement the Monoid operations for M"。

请注意,传递给 reflect 的实际值 a 未被使用,它仅作为类型 M a s 的 "proxy" 传递,告诉 reflect 使用哪种类型 (s) 到 "bring back the record".

实际的本地实例是使用reify函数构造的:

withMonoid :: (a -> a -> a) -> a -> (forall s. Reifies s (Monoid_ a) => M a s) -> a
withMonoid f z v = reify (Monoid_ f z) (runM . asProxyOf v)

asProxyOf :: f s -> Proxy s -> f s
asProxyOf a _ = a

asProxyOf 函数是一种技巧,可以让编译器相信在幺半群中使用的幻像类型与 reify 提供的 Proxy 中使用的幻像类型相同。