【问题标题】:Function from `mappend` function to `Monoid` instance?从`mappend`函数到`Monoid`实例的函数?
【发布时间】:2015-04-23 08:44:23
【问题描述】:

我有一个数据结构(它是玫瑰树的一个特定子类,它形成一个具有最大下界和最小上界函数的格),它支持两个完全合理的函数来充当Monoid 类的@ 987654324@。

有没有办法在haskell 中支持匿名Monoid 实例?这是我应该考虑使用 Template-Haskell 之类的东西为我生成类型类的实例吗?

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

【问题讨论】:

  • 如果您有多个实例并且不想在任何地方使用newtypes,您可以将pass a "Monoid" dictionary around manually 用作data RTMonoid a = { empty :: RT a, append :: RT a -> RT a -> RT a}rt1 :: RTMonoid a; rt1 = RTMonoid ...rt2 :: RTMonoid a; rt2 = RTMonoid ...,然后您可以编写函数来接受您使用的 RTMonoid a 参数。手动传递它有点笨拙,但它使它更具可扩展性。如果您只有 2 个实例,请使用新类型。
  • 您根本没有必须选择默认值——强制用户选择使用新类型可能会更好。您还可以对mergeThisWaymergeThatWay 使用单独的函数。
  • 您可以使用hackage.haskell.org/package/lattices 中的类型类 就我个人而言,我希望在Haskell 中更频繁地使用格子。它们是如此有用的结构。

标签: haskell types metaprogramming


【解决方案1】:

可以使用reflection 包中的工具即时创建Monoid 的“本地”实例。存储库中有一个ready-made example。这个答案解释了一点。

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

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

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

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

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)

它说:“只要s是我们Monoid字典Monoid_的类型级表示,我们就可以将其反射回来获取字典,并使用字段来实现@的Monoid操作987654340@".

请注意,传递给reflect 的实际值a 没有被使用,它仅作为M a s 类型的“代理”传递,它告诉reflect 使用哪种类型(s)来“带回记录”。

实际的本地实例是使用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 函数是一种技巧,可以让编译器相信 monoid 中使用的幻像类型与 reify 提供的 Proxy 中的幻像类型相同。

【讨论】:

  • 如何使用withMonoid 的示例将大大增加Data.Reflection 上的介绍性文献。
  • @Cirdec 另一个很好的例子是动态生成FromJSON/ToJSON 类型的实例,这取决于在运行时获得的信息。例如,要求用户为每个字段名称添加前缀。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-26
  • 1970-01-01
  • 2018-10-12
  • 1970-01-01
  • 2015-10-01
相关资源
最近更新 更多