如何统一这些类型?

How to unify these types?

我有以下来自 purescript-express 的代码(但问题更笼统)。

setHandler :: forall e. Handler e
setHandler = do
    idParam   <- getRouteParam "id"
    send "Yeah! "

appSetup :: forall e. App e
appSetup = do
    get "/set/:id" setHandler

setHandler 需要具有给定的签名,因为 get 定义为

> :t get
forall e r.
(RoutePattern r) => r
                    -> HandlerM ( express :: EXPRESS | e ) Unit
                    -> AppM ( express :: EXPRESS | e ) Unit

但是现在我想在 setHandler

中使用以下函数
getPointsSet :: forall f. String -> Aff ( fs :: FS | f ) Foobar

这将给我以下编译器错误

[1/1 TypesDoNotUnify] src/Main.purs:31:5

          v
  31      send "Yeah! "
          ^

  Could not match type

    HandlerM

  with type

    Aff

  while trying to match type HandlerM
                               ( express :: EXPRESS
                               | _2
                               )
    with type Aff
                ( fs :: FS
                | _0
                )
  while checking that expression send "Yeah! "
    has type Aff
               ( fs :: FS
               | _0
               )
               _1
  in value declaration setHandler

我知道使用 getPointsSet 有效地需要 setHandler 也变成 Aff 但是我不能用 get 连接它。

编辑

如果我尝试按照以下答案中的建议添加 liftAff

setHandler :: forall e. Handler e
setHandler = do
    idParam   <- getRouteParam "id"
    liftAff $ getPointsSet "../some-data.csv"
    send "Yeah! "

我收到以下错误

[1/1 NoInstanceFound] src/Main.purs:28:1
   28  setHandler :: forall e. Handler e
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   No type class instance was found for
   Control.Monad.Aff.Class.MonadAff ( fs :: FS | _0 )
                                 (HandlerM ( express :: EXPRESS | e0 ))

The instance head contains unknown type variables. Consider adding a type annotation.
in value declaration setHandler

我需要做什么来解决这个问题?

似乎HandlerMMonadAff的实例,所以你可以使用liftAff。喜欢这里:

setHandler :: forall e. Handler e
setHandler = do
  idParam   <- getRouteParam "id"
  liftAff $ getPointsSet "foo"
  send "Yeah! "

啊,抱歉,如果没有 appSetupsetHandler

的附加注释,行不会统一

更新版本

appSetup :: forall e. App (fs :: FS|e)
appSetup =
  get "/set/:id" setHandler

setHandler :: forall e. Handler (fs :: FS|e)
setHandler = do
  idParam   <- getRouteParam "id"
  liftAff $ getPointsSet "../some-data.csv"
  send "Yeah! "

您还需要更改 main 类型

main :: forall e. Eff (express :: EXPRESS, fs :: FS|e) Unit

为了扩展 Максим 的回答,

您的 setHandler 的类型 forall e. Handler e 等同于 HandlerM (express :: EXPRESS | e) Unit 这又相当于 HandlerM (Request -> Response -> Eff (express :: EXPRESS | e) Unit -> Aff (express :: EXPRESS | e) Unit)。如果我们从构造函数中取出函数并为其提供参数(就像某些函数可能在幕后所做的那样),我们将得到 Aff (express :: EXPRESS | e) Unit)

您的 getPointsSet 的类型为 forall f. String -> Aff ( fs :: FS | f ) Foobar

所以基本上我们的问题可以简化为:(express :: EXPRESS | e) 类型不与 ( fs :: FS | f ) 统一,这意味着为了从 setHandler 调用 getPointsSet , setHandler 必须提供一个 String(您提供 "foo")和它目前不提供的效果 FS。为了提供它,setHandler 的类型签名必须改变,所以我们想要 Aff (express :: EXPRESS, fs :: FS | r) 而不是 Aff (express :: EXPRESS | e) Unit)。现在还需要对 mainsetHandler 进行完全相同的分析,setHandler 需要 main 不提供的效果 FS。需要进行相同的更改。

我希望这是有道理的。