
The job type is not a type in the Haskell sense. It is a just a value.
Promoting it to a type just creates the problem you are trying to solve.
The mechanism in Haskell that selects some value given another value is the
function so why not write a function JobType -> Job -> App () that selects
the right job running function for the given job type?
On Wed, Jul 5, 2017 at 10:11 AM Matt
You are asking GHC to select an instance of a type class (a compile-time operation) at run-time. I believe that this is possible with something like the exinst[1] package and runtime dictionaries with the constraints[2] package, but you're getting into some fairly hairy territory. I don't think that this would end up providing a nice UX for library consumers, either, as you end up needing user-defined singleton types to lift that information into the type level -- eg, a sum type of operations that the user supports, and then an open data family (or GADT) indexed by that sum type. In order for runJob to know about it, the class definition needs to know about that index, which kind of ruins the point of the class -- if you're going to keep a closed type of operations, you might as well just have:
data Job = SyncContact SyncContactJob | ImportFoo ImportFooJob
data SyncContactJob = SyncContactJob { userId :: UserId } data ImportFooJob = ImportFooJob { fooId :: FooId }
runJob :: Job -> App ()
The main benefit to the existentialized approach, IMO, is when the actions are entirely derived from type class operations. Sandy Maguire gave a good talk on the approach at Lambdaconf [3]. Since much of the behavior here is ad hoc, then I think you'll get less utility out of the class.
We have a similar sort of framework on our projects at work, but using Amazon SQS messages instead of a database. The function has a signature like:
pollSqsFor :: FromJSON a => SqsQueue -> (a -> App b) -> App ()
This lets us write `pollSqsFor ImportThing (thingImporter :: ThingRequest -> App ())` for the workers that end up processing it, with the polling function handling stuff like delay time, error handling, keeping the message invisible, deleting it if successful, etc. This sort of thing would be easy to port to using a database, the only difference being loading only matching rows from the database for the given type.
[1] exinst: https://hackage.haskell.org/package/exinst [2] contraints: http://haddock.stackage.org/lts-5.1/constraints-0.8/Data-Constraint.html [3] some1 like you: http://reasonablypolymorphic.com/some1-like-you/#/title
Matt Parsons
On Wed, Jul 5, 2017 at 6:56 AM, Saurabh Nanda
wrote: 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?
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
_______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.