Trouble with writing a generic rabbitmq event handler - No type class instance was found

I’m working on a prototype of a microservice in purescript that uses my rabbitmq client wrapper written in js. Purescript code has to provide a handler that will be called when new event is received. The handler takes json object and a trace (string array) and should return a promise.

I wanted the subscribe function to take a -> Trace -> Aff Unit hander function and wire it to the required Json -> Trace -> Effect (Promise Unit) handler

It worked for a concrete type, but I have trouble changing it to a more generic implementation.

Here’s my code:

import Prelude
import Control.Promise (Promise, fromAff, toAffE)
import Effect (Effect)
import Effect.Class (liftEffect)
import Effect.Aff (Aff)
import Data.Either (Either, fromRight)
import Partial.Unsafe (unsafePartial)
import Data.Argonaut (Json)
import Data.Argonaut.Decode.Class (class DecodeJson, decodeJson)
import Data.Argonaut.Decode.Error (JsonDecodeError)

type Handler a
  = forall a. DecodeJson a => a -> Trace -> Aff Unit

type PromiseHandler
  = Json -> Trace -> Effect (Promise Unit)

newtype Trace
  = Trace (Array String)

foreign import _bind ::  MqContext -> String -> PromiseHandler -> Effect (Promise Unit)

subscribe :: forall a. DecodeJson a => MqContext -> String -> Handler a -> Aff Unit
subscribe ctx route handler = toAffE $ _bind ctx route (toPromiseHander handler)

toPromiseHander :: forall a. DecodeJson a => Handler a -> PromiseHandler
toPromiseHander handler event trace = fromAff $ handler decoded trace
  where
  decoded :: a
  decoded = unsafePartial $ fromRight $ decodeJson event

Js part:

exports._bind = mq => route => handler => () => {
  return mq.bind(route, (e, t) => handler(e)(t)())
}

Intended usage:

main :: Effect Unit
main =
  launchAff_ do
    Console.log "Starting"
    let ctx = Mq.create "ps"
    Mq.connect ctx
    Mq.subscribe ctx "event.ps.test" (eventPsTest ctx)
    Mq.ready ctx

eventPsTest :: MqContext -> Handler TestMsg
eventPsTest ctx event trace = do
  Console.log $ "received: " <> show event <> "  " <> show trace
  Mq.publish ctx "event.ps.publish" "test" trace
  pure unit

newtype TestMsg
  = TestMsg { foo :: String }

derive newtype instance decodeJsonTestMsg :: DecodeJson TestMsg

derive newtype instance showTestMsg :: Show TestMsg

The error I get:

  No type class instance was found for
                                            
    Data.Argonaut.Decode.Class.DecodeJson t0
                                            
  The instance head contains unknown type variables. Consider adding a type annotation.

while applying a function toPromiseHander
  of type DecodeJson t0 => (forall a. DecodeJson a => a -> Trace -> ...) -> Json -> Trace -> Effect ...
  to argument handler
while checking that expression toPromiseHander handler
  has type Json -> Trace -> Effect (Promise Unit)
in value declaration subscribe

where t0 is an unknown type

What am I missing?

Thanks for any help :slight_smile:

You should probably change this to


type Handler a
  = a -> Trace -> Aff Unit

It works… thanks :slight_smile: