函数从`mappend`函数到`Monoid`实例? [英] Function from `mappend` function to `Monoid` instance?
问题描述
我有一个数据结构(它是玫瑰树的一个特定的子类,它形成了具有最大下界和最小上界函数的格),并且它支持两个完全合理的函数来充当 Monoid
类的 mappend
。
有没有办法在haskell中支持匿名 Monoid
实例?这是一个实例,我应该考虑使用类似Template-Haskell的东西来为我生成我的类型类?
我喜欢的是 makeMonoid ::(RT a - > RT a - > RT a) - > Monoid a
让我可以即时创建实例,但据我所知,这与库存类型系统是不一致的。
如果我只需要选择一个默认的合并函数并为其他合并写 newtype
s,只需要好奇就可以了
b
这是一个新类型的包装类型 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
实例定义
mappend ab = M $ mappend_(反映a)(runM a)(runM b)
mempty = a其中a = M $ mempty_(反映a)
它表示:每当 s
是类型级表示我们的 Monoid
字典 Monoid _
,我们可以反射它来获取字典,并使用字段来实现<$对于 M
。
请注意,实际值 a
传递给 reflect
没有被使用,它只是作为
反映
用于带回记录的类型( 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 newtype
s 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屋!