Overall context: I'm trying to port the DelayedJob library from Ruby/Rails world to Haskell. The basic idea is to serialise a job and write it to the DB, deserialise it, and run the job using a job-runner function, which is determined by the job-type.

I'm using a type-class to define the custom job-runner, something on the lines of:

    class (FromJSON j, ToJSON j) => DelayedJob j where
      runJob :: j -> AppM ()

    data SyncContactsJob = SyncContactsJob { userId :: UserId } deriving (Eq, Show, Generic, FromJSON, ToJSON)

    instance DelayedJob SyncContactsJob where
      runJob job = do
        -- entire job execution logic comes here

Is there **any** type-system hackery, that will let me take a runtime value, eg. "SyncContactsJob", "DoBackupJob", and use that to run the correct version of the `runJob` function? That is,  how do I write the following function:

   invokeJob :: JobId -> AppM ()
   invokeJob jid = do
       jobRow <- fetchJob jid
       let jtype = jobRow ^. jobtype -- this will have "SyncContactsJob"
            jvalue = jobRow ^. jobdata -- this will have a Data.Aeson.Value
       runJob (......) -- QUESTION: What do I write here to make this compile?