Polysemy 1.6.0使用raiseUnder注入效果时触发无限类型匹配错误
错误原因
首先拆解你遇到的类型报错本质:
你当前的runMemoizationState'的返回值要求是InterpreterFor (Memoization k v) r,也就是类型为Sem (Memoization k v : r) a -> Sem r a的函数。你使用.组合三个函数的时候,编译器推导发现:
raiseUnder调用后的输出效应栈是Memoization k v : State (M.Map k v) : r- 经过
runMemoizationState f消掉Memoization效应后,栈变成State (M.Map k v) : r - 经过
evalState mempty消掉State效应后,栈应该变成r,理论上正好符合返回类型要求。
但触发无限类型错误的核心原因是:Polysemy 1.6.0版本中.组合器对高阶类型的推导存在限制,无法自动匹配多态的效应栈变量,和你预期的raiseUnder行为没有冲突,只是编译器推导能力不足导致的。
修复方案
两种可直接运行的修复方式:
方案1:放弃.组合,显式传入参数
不需要调整函数逻辑,只要把点组合改成显式参数传递,帮编译器确定类型即可:
runMemoizationState' :: forall k v r. ( Ord k ) => (k -> Sem r v) -> InterpreterFor (Memoization k v) r runMemoizationState' f sem = evalState mempty $ runMemoizationState (raise . f) $ raiseUnder @(State (M.Map k v)) @(Memoization k v) @r sem
这里额外给f加了raise提升,是为了帮编译器确认f的效应栈可以兼容插入了State的新栈,避免额外的推导错误。
方案2:用reinterpret绕开手动效应注入
你可以完全不用手动调用raiseUnder,直接用reinterpret实现局部State的注入,代码更简洁,也不会触发类型推导问题:
runMemoizationState' :: forall k v r. ( Ord k ) => (k -> Sem r v) -> InterpreterFor (Memoization k v) r runMemoizationState' f = evalState M.empty . reinterpret (\case FetchMemoized k -> do memoized <- get @(M.Map k v) case memoized M.!? k of Just memoizedResult -> return memoizedResult Nothing -> do result <- raise $ f k modify' $ M.insert k result return result )
这个实现和你原来的逻辑完全等价,只是把runMemoizationState的逻辑合并到了reinterpret里,避开了手动处理效应栈提升的步骤。
内容的提问来源于stack exchange,提问作者GlinesMome
相关产品推荐
相关产品推荐

