从 `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
让我即时创建实例,但我知道这与我理解的股票类型系统不一致。
如果我只需要选择一个默认合并函数并为其他合并编写 newtype
s,我可以接受,只是好奇
您可以使用存储库reflection package. There's a ready-made example中的工具即时创建Monoid
的"local"个实例。这个答案稍微解释一下。
这是对 a
类型值的新类型包装器,我们将在其上定义我们的 Monoid
实例。
newtype M a s = M { runM :: a } deriving (Eq,Ord)
请注意,有一个幻影类型 s
没有出现在右侧。它将携带本地 Monoid
实例工作所需的额外信息。
这是一条记录,其字段代表Monoid
class的两个操作:
data Monoid_ a = Monoid_ { mappend_ :: a -> a -> a, mempty_ :: a }
以下是 M
的 Monoid
实例定义:
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
中使用的幻像类型相同。
我有一个数据结构(它是rose-tree的一个特定子class,它形成了一个具有最大下限和最低上限函数的格子),它支持两个非常合理的函数来服务作为 Monoid
class 的 mappend
。
有什么方法可以在 haskell 中支持匿名 Monoid
实例吗?这是我应该考虑使用诸如 Template-Haskell 之类的东西来为我生成类型 classes 的实例吗?
我想要的是 makeMonoid :: (RT a -> RT a -> RT a) -> Monoid a
让我即时创建实例,但我知道这与我理解的股票类型系统不一致。
如果我只需要选择一个默认合并函数并为其他合并编写 newtype
s,我可以接受,只是好奇
您可以使用存储库reflection package. There's a ready-made example中的工具即时创建Monoid
的"local"个实例。这个答案稍微解释一下。
这是对 a
类型值的新类型包装器,我们将在其上定义我们的 Monoid
实例。
newtype M a s = M { runM :: a } deriving (Eq,Ord)
请注意,有一个幻影类型 s
没有出现在右侧。它将携带本地 Monoid
实例工作所需的额外信息。
这是一条记录,其字段代表Monoid
class的两个操作:
data Monoid_ a = Monoid_ { mappend_ :: a -> a -> a, mempty_ :: a }
以下是 M
的 Monoid
实例定义:
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
中使用的幻像类型相同。