我正在尝试使用数据类型点菜的方法来定义一个免费的 monad 用于模板目的。我写了一些组合器,但我被卡住了。我的程序不断分歧,我不明白为什么。
考虑:
math :: Math :<: f => MathExpr a -> Free f ()
blank :: f :<: (Textual :+: Math) => Free f () -> Free (Blank k f) ()
equals :: Free (Math :+: (Blank L Math)) ()
-> Free (Math :+: (Blank R Math)) ()
-> Free Equation ()
组合(空白。数学)具有以下类型:
blank . math :: ( f :<: (Textual :+: Math)
, Math :<: f
) => MathExpr a -> Free (Blank k f) ()
请注意,f 必须同时小于 Textual 和 Math 的连接,并且大于 Math。所以 f 的唯一可能性是数学。(我意识到如果没有我的更多工作,编译器无法推断出这一点,如果有的话)
当我尝试评估时会出现问题:
test :: Free Equation ()
test = (hoistFree (inj :: Blank 'L Math a -> (Math :+: Blank 'L Math) a)
. blank
. (math :: MathExpr x -> Free Math ())
$ "hi"
)
`equals` (math $ "world")
这显然是循环的,将我的 CPU 固定在 100%。计算将其结果打印为:
Free (Equation (Free (DirectSum {unDirectSum = Right
此时该值被截断并且 GHCi 退出。因此,它显然可以确定 equals 的第一个参数位于直接和的后半部分,但它似乎无法计算空白。
我所有的功能都是完整的,我在这里看不到底部,但我从来都不擅长定点组合器。有任何想法吗?
编辑:带有免费 monad 的模块现在位于: http ://lpaste.net/93471 模块 Data.Domain 位于:http ://lpaste.net/93472