Reputation: 9914
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
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
Reputation: 101
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