robkuz
robkuz

Reputation: 9914

How to unify these types?

I have the following code from purescript-express (but the question is more general).

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

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

setHandler needs to have the given signature as get is defined as

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

Now however I want to use the following function within setHandler

getPointsSet :: forall f. String -> Aff ( fs :: FS | f ) Foobar

which will give me the following compiler error

[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

I understand that using getPointsSet effectively requires setHandler to become a Aff as well but than I cannot wire it up with the get then.

Edit

If I try to add a liftAff as suggested in the answer below

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

I get the following error

[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

What do I need to do to resolve that?

Upvotes: 1

Views: 493

Answers (2)

soupi
soupi

Reputation: 1013

To expand upon Максим's answer,

Your setHandler has the type forall e. Handler e which is equivalent to HandlerM (express :: EXPRESS | e) Unit which in turn is equivalent to HandlerM (Request -> Response -> Eff (express :: EXPRESS | e) Unit -> Aff (express :: EXPRESS | e) Unit). if we take out the function from the constructor and feed it with arguments (as some function probably does behind the scenes) we are left with Aff (express :: EXPRESS | e) Unit)

Your getPointsSet has the type forall f. String -> Aff ( fs :: FS | f ) Foobar

So basically our problem can be reduced to this: the type (express :: EXPRESS | e) does not unify with ( fs :: FS | f ), this means that in order to call getPointsSet from setHandler, setHandler has to supply a String (you supplied "foo") and the effect FS which it currently does not supply. in order to supply it, the type signature of setHandler has to change, so instead of Aff (express :: EXPRESS | e) Unit) we want to have Aff (express :: EXPRESS, fs :: FS | r). now the exact same analysis needs to be done for main and setHandler as well, setHandler needs the effect FS which main does not supply. the same change will need to be made.

I hope this make sense.

Upvotes: 1

It seems that HandlerM has instance of MonadAff, so you can use liftAff. Like here:

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

Ah, sorry, rows don't unify without additional annotation of appSetup and setHandler

updated version

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! "

You need to alter main type also

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

Upvotes: 5

Related Questions