【问题标题】:How do I resolve a type error using Enter from the Servant library?如何使用 Servant 库中的 Enter 解决类型错误?
【发布时间】:2017-01-21 18:41:52
【问题描述】:

我正在尝试使用 enter 函数来运行我的 API 处理程序,其中包含一组异常,我将在高级别的情况下将这些异常转换为 Servant,但是我在类型匹配方面遇到了麻烦。

鉴于这组最小的定义:

-- server :: Config -> Server Routes
server :: Config -> ServerT Routes (ExceptT ServantErr IO)
server c = enter runApp (handlers c)

-- runApp :: AppM :~> Handler
runApp :: ExceptT AppErr IO :~> ExceptT ServantErr IO
runApp = Nat undefined

handlers :: Config -> ServerT Routes (ExceptT AppErr IO)
handlers = undefined

我最终遇到了这种类型的错误:

Couldn't match type `IO' with `ExceptT ServantErr IO'
arising from a functional dependency between:
  constraint `servant-0.7.1:Servant.Utils.Enter.Enter
                (IO ResponseReceived)
                (ExceptT AppErr IO :~> ExceptT ServantErr IO)
                (IO ResponseReceived)'
    arising from a use of `enter'
  instance `servant-0.7.1:Servant.Utils.Enter.Enter
              (m a) (m :~> n) (n a)'
    at <no location info>
In the expression: enter runApp (handlers c)
In an equation for `server': server c = enter runApp (handlers c)

异常来自调用enter 的行。供参考,enter的声明:

class Enter typ arg ret | typ arg -> ret, typ ret -> arg where
  enter :: arg -> typ -> ret

instance Enter (m a) (m :~> n) (n a) where
  -- enter :: (m :~> n) -> m a -> n a

所以,当我打电话给enter runApp 时,我希望类型是这样的:

enter :: (m :~> n) -> m a -> n a
enter (runApp :: m ~ ExceptT AppErr IO :~> n ~ ExceptT ServantErr IO) :: ExceptT AppErr IO a -> ExceptT ServantErr IO a

(上面我使用n ~ ExceptT ServantErr IO 来说明我的类型替换)

实际上,我从其他代码中知道(我试图模仿,但我不明白我哪里出错了),enter runApp 应该/必须有这种类型:

enter runApp :: ServerT Routes (ExceptT AppErr IO a) -> ServerT Routes (ExceptT ServantErr IO a)

所以,问题很多:

  • enter runApp 的实际类型是什么(不是 ghci 会给我的,而是更具描述性的解释)?
  • (IO ResponseReceived)约束来自哪里?
  • 如何调整上述代码以使整个处理程序通过自然转换?

【问题讨论】:

  • Routes 的外观如何?我不确定这是否在新版本的servant 中得到解决,但你不能在路由中有Raw 端点;如果你这样做了,结果是一个奇怪的类型错误。
  • 原来这是正确的答案!您能否将您的回复升级为答案,以便我给您信用?

标签: haskell servant


【解决方案1】:

Api 类型中不能有Raw 端点。这样做的方法是将原始端点从handlers 中取出并调用它,例如

server c = enter runApp (handlers c) :<|> handleRaw

【讨论】:

    猜你喜欢
    • 2021-03-18
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    • 2016-01-25
    • 1970-01-01
    • 2021-12-21
    • 2019-09-15
    • 1970-01-01
    相关资源
    最近更新 更多