mardi 25 décembre 2018

using type classes to provide alternative implementations for when using Acid-State

I wrote a web application using scotty and acid state, now i would like to use type classes to be able to provide alternative implementations for the capabilities of my application for testing. I get the general idea of it and am able to apply it so simple examples but since im am using acid state there are a lot of type classes and template haskell involved which i am not entirely comfortable with yet.

so i have these straight-forward classes for the different capabilities

class Logging m where
  log :: T.Text -> m ()

class Server m where
  body :: m B.ByteString
  respond :: T.Text -> m ()
  setHeader :: T.Text -> T.Text -> m ()

class Db m where
  dbQuery :: (MethodState event ~ Database,QueryEvent event) => event -> m (EventResult event)
  dbUpdate :: (MethodState event ~ Database,UpdateEvent event) => event -> m (EventResult event)

and i also provided instances for them for my "production" monad.

But when it comes to the database capability i cant get to work what i want.

the class looks like this

class Db m where
  dbQuery :: (MethodState event ~ Database,QueryEvent event) => event -> m (EventResult event)
  dbUpdate :: (MethodState event ~ Database,UpdateEvent event) => event -> m (EventResult event)

and the instance for the production monad works fine since it only passes the event to the update and query functions of acid state, but for a test monad i would like to have something like this: instance Db Test where dbQuery (GetVersion) = use (testDb . clientVersion) dbQuery (GetUser name) = preuse (testDb . users . ix name) dbUpdate (PutUser name user) = users %= M.insert name user ... so that I can match on GetVersion,GetUser etc. (which are generated by the template haskell function makeAcidic ... ) and specify how they should be handled in the test environment.

But I get the error:

Could not deduce: event ~ GetVersion
from the context: (MethodState event ~ Database, QueryEvent event)
  bound by the type signature for:
              dbQuery :: (MethodState event ~ Database, QueryEvent event) =>
                        event -> Test (EventResult event)
  at Main.hs:88:3-9
‘event’ is a rigid type variable bound by
  the type signature for:
    dbQuery :: forall event.
                (MethodState event ~ Database, QueryEvent event) =>
                event -> Test (EventResult event)
  at Main.hs:88:3
• In the pattern: GetVersion
In an equation for ‘dbQuery’:
    dbQuery (GetVersion) = use (testDb . clientVersion)
In the instance declaration for ‘Db Test’
• Relevant bindings include
  dbQuery :: event -> Test (EventResult event)
    (bound at Main.hs:88:3)

i guess thats because GetVersion, GetUser etc. all have a their different own types. So is there a way to do this?

Aucun commentaire:

Enregistrer un commentaire