【发布时间】:2021-07-14 20:11:42
【问题描述】:
我正在将代码库转换为使用polysemy,并且在转换我对LFresh typeclass from unbound-generics 的使用时遇到了麻烦。我需要的两个操作都有签名
avoid :: LFresh m => [AnyName] -> m a -> m a
lunbind :: (LFresh m, Alpha p, Alpha t) => Bind p t -> ((p, t) -> m c) -> m c
显然是高阶的。我想创建一个与LFresh 类对应的效果,并通过unbound-generics 提供的LFreshM monad 运行它。这是我迄今为止尝试过的,使用Final,因为这似乎让我比Embed更父亲(我很高兴让LFreshM始终是效果堆栈中的最后一件事):
import Polysemy
import Polysemy.Final
import qualified Unbound.Generics.LocallyNameless as U
data LFresh m a where
Avoid :: [U.AnyName] -> m a -> LFresh m a
LUnbind :: (U.Alpha p, U.Alpha t) => U.Bind p t -> ((p,t) -> m c) -> LFresh m c
makeSem ''LFresh
runLFresh :: Member (Final U.LFreshM) r => Sem (LFresh ': r) a -> Sem r a
runLFresh = interpretFinal @U.LFreshM $ \case
Avoid xs m -> do
m' <- runS m
pure (U.avoid xs m')
LUnbind b k -> do
k' <- bindS k
pure (U.lunbind b k')
然而,LUnbind 的情况自 k' :: f (p, t) -> U.LFreshM (f x) 以来不进行类型检查,但它期望 (p, t) -> U.LFreshM (f x) 类型的东西作为 U.lunbind 的第二个参数;注意k' 类型中额外的f。
我还有其他模糊的想法,但我先把它留在那里,很高兴进一步澄清。甚至不确定我是否走在正确的轨道上。最终,我的真正目标只是“让多义词从 unbound-generics 与 LFresh 一起工作”,所以如果有更好的、完全不同的方法来实现,我也很高兴听到它。
【问题讨论】:
-
我在主题中说“CPS 风格”的原因是
lunbind采用Bind和 continuation 指定如何处理解构绑定的方式.问题似乎是bindS假设 Kleisli 箭头的输入将是另一个单子动作的结果,在调用runS之后,该动作最终将包裹在f中。但是,这里不是这样。