如何统一这些类型?

时间:2016-03-21 19:33:35

标签: types purescript

我有来自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

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

2 个答案:

答案 0 :(得分:5)

似乎HandlerM的实例为MonadAff,因此您可以使用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

答案 1 :(得分:1)

扩展Максим的答案,

您的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 )统一,这意味着为了从getPointsSet调用setHandler,{ {1}}必须提供setHandler(您提供的String)和当前不提供的效果"foo"。为了提供它,FS的类型签名必须更改,因此我们希望setHandler代替Aff (express :: EXPRESS | e) Unit)。现在需要对Aff (express :: EXPRESS, fs :: FS | r)main进行完全相同的分析,setHandler需要主要不提供的效果setHandler。需要做出同样的改变。

我希望这是有道理的。