我有一个数据结构(它是玫瑰树的一个特定子类,它形成一个具有最大下界和最低上界函数的格),它支持两个完全合理的函数作为Monoid类的mappend。
在haskell中有任何方法支持匿名Monoid实例吗?在这种情况下,我应该考虑使用诸如Template-Haskell之类的东西来为我生成类型类吗?
我想要的是一个让我动态创建实例的makeMonoid :: (RT a -> RT a -> RT a) -> Monoid a,但我理解这与我所理解的股票类型系统是不一致的。如果我只需要选择一个默认的合并函数并为其他合并编写newtype,我就没问题了,只是好奇
发布于 2015-02-21 22:09:49
您可以动态地创建Monoid的“本地”实例,使用反射包中的工具。存储库中有一个现成的例子。这个答案解释了一点。
这是一个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 }下面是用于Monoid的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)它说:“每当s是我们的Monoid字典Monoid_的类型级表示时,我们就可以将它反射回来以获得字典,并使用字段为M实现Monoid操作”。
注意,传递给reflect的实际值reflect没有使用,它只是作为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 _ = aasProxyOf函数是一种使编译器相信在单面体中使用的幻影类型与reify提供的Proxy中的幻影类型相同的技巧。
https://stackoverflow.com/questions/28649854
复制相似问题