函数从`mappend`函数到`Monoid`实例? [英] Function from `mappend` function to `Monoid` instance?

查看:129
本文介绍了函数从`mappend`函数到`Monoid`实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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



我喜欢的是 makeMonoid ::(RT a - > RT a - > RT a) - > Monoid a 让我可以即时创建实例,但据我所知,这与库存类型系统是不一致的。
如果我只需要选择一个默认的合并函数并为其他合并写 newtype s,只需要好奇就可以了
b

解决方案 可以动态地创建 Monoid 的本地实例,使用思考包中的工具。存储库中有一个现成的示例。这个答案解释了一点。



这是一个新类型的包装类型 a ,我们将定义我们的 Monoid 实例。

  newtype M as = M {runM: :a}派生(Eq,Ord)

请注意,有一个幻像类型 s 不出现在右侧。它将为本地 Monoid 实例运行所需的额外信息。



这是一个记录,其字段表示 Monoid class的两个操作:

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

以下是 Monoid b
实例定义 Monoid_a)=> Monoid(M as)其中
mappend ab = M $ mappend_(反映a)(runM a)(runM b)
mempty = a其中a = M $ mempty_(反映a)

它表示:每当 s 是类型级表示我们的 Monoid 字典 Monoid _ ,我们可以反射它来获取字典,并使用字段来实现<$对于 M

请注意,实际值 a 传递给 reflect 没有被使用,它只是作为 code>,它告诉反映用于带回记录的类型( s )。



实际本地实例是使用

  withMonoid ::>  reify  (a  - > a  - > a) - > a  - > (通知s(Monoid_a)=> M a s) - > a 
withMonoid f z v = reify(Monoid_ f z)(runM。asProxyOf v)

asProxyOf :: f s - >代理s - > fs
asProxyOf a _ = a

asProxyOf 函数是哄骗编译器说明monoid中使用的幻像类型与提供的 Proxy 中的幻像类型相同的技巧。 reify


I have a data structure (it's a specific subclass of rose-tree that forms a lattice with greatest-lower bound and lowest-upper bound functions), and it supports two perfectly reasonable functions to serve as the Monoid class's mappend.

Is there any way to support anonymous Monoid instances in haskell? Is this an instance where I should consider using something like Template-Haskell to generate my typeclasses for me?

What I'd love is a makeMonoid :: (RT a -> RT a -> RT a) -> Monoid a to let me create the instance on the fly, but I understand that that's incoherent with the stock typesystem as I understand it. I'm okay with it if I just need to pick a default merge function and write newtypes for other merges, just curious

解决方案

You can create "local" instances of Monoid on the fly, using the tools in the reflection package. There's a ready-made example in the repository. This answer explains it a little.

This is a newtype wrapper over values of type a, on which we will define our Monoid instance.

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

Notice that there is a phantom type s that does not appear in the right hand side. It will carry extra information necessary for the local Monoid instance to work.

This is a record whose fields represent the two operation of the Monoid class:

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

The following is the Monoid instance definition for M:

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)

It says: "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".

Notice that the actual value a passed to reflect is not used, it is passed only as a "proxy" of type M a s that tells reflect which type (s) to use to "bring back the record".

The actual local instance is constructed using the reify function:

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

The asProxyOf function is a trick to convince the compiler that the phantom type used in the monoid is the same as the one in the Proxy supplied by reify.

这篇关于函数从`mappend`函数到`Monoid`实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆