[Haskell-cafe] Instantiating a typeclass based on a runtime value?

Rein Henrichs rein.henrichs at gmail.com
Wed Jul 5 17:52:08 UTC 2017


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 <parsonsmatt at gmail.com> wrote:

> 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 <saurabhnanda at gmail.com>
> 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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20170705/1bf6109c/attachment.html>


More information about the Haskell-Cafe mailing list