You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:06:03