我正在阅读documentation on monad layers package,我的大脑将会沸腾。
在本文档的mmtl
部分,作者讨论了不变函子。方法invmap
与fmap
的{{1}}类似,但它也需要反态射Functor
。我理解为什么作者说(b -> a)
的{{1}}比hoist
的{{1}}更强大,但我不明白这种反型态射的重点是什么。
是否有MFunctor
的例子不能是tmap
的实例?
答案 0 :(得分:4)
这是Invariant
显示的标准位置---用于嵌入lambda演算的高阶抽象语法(HOAS)。在HOAS中,我们喜欢编写表达式类型,如
data ExpF a
= App a a
| Lam (a -> a)
-- ((\x . x) (\x . x)) is sort of like
ex :: ExpF (ExpF a)
ex = App (Lam id) (Lam id)
-- we can use tricky types to make this repeat layering of `ExpF`s easier to work with
我们希望此类型具有类似Functor
的结构,但令人遗憾的是,Lam
具有a
的正面和负面位置都不可能。所以我们定义
instance Invariant ExpF where
invmap ab ba (App x y) = App (ab x) (ab y)
invmap ab ba (Lam aa) = Lam (ab . aa . ba)
这真的很悲惨,因为我们真正想做的是将这个ExpF
类型折叠起来以形成一个递归表达式树。如果它是一个明显的Functor
,但由于它不是我们得到一些非常丑陋,具有挑战性的结构。
要解决此问题,请添加另一个类型参数并将其命名为Parametric HOAS
data ExpF b a
= App a a
| Lam (b -> a)
deriving Functor
我们最终发现我们可以使用Functor
实例在此类型上构建一个自由monad,其中绑定是变量替换。非常好!