[Haskell-cafe] Declaring Functors for Type constrained data types

Guru Devanla gurudev.devanla at gmail.com
Wed Mar 1 14:11:30 UTC 2017

Just to make sure I understand. In my initial example, the following are
all types and I wanted the dispatch to happen on this types once they are
instances of the Taskable type class.

-- task 1
data UpdateAcctsTask = UpdateAccts

-- task 2
data EmailConfig = EmaiConfig {someattrs::String}
data SendEmailTask = SendEmailsTask EmailConfig

-- task 3
data GeneralWriterTask a = GeneralWriterTask a

Now, later on I expect users to create more types which are all say,
instances of Taskable typeclass.  So, here I do not expect to have any
dispatch based on value, but based on types.

On Wed, Mar 1, 2017 at 5:24 AM, Patrick Chilton <chpatrick at gmail.com> wrote:

>  Is that thinking usually an anti-pattern.
> Typeclasses choose between implementations of a method based on static
> *types* known at compile time. In OOP, which implementation of an
> interface method you get depends on the run-time object *instance*.
> They're not really related despite the similarities.
> For example, if you have a list of widgets and you want to do something
> different depending on what their run-time value is, a typeclass would be
> the wrong thing to use since it dispatches on types, not values. It's
> possible to make them work a little bit like OOP classes, but then you end
> up with the classic antipattern.
> On Wed, Mar 1, 2017 at 2:16 PM, Guru Devanla <gurudev.devanla at gmail.com>
> wrote:
>> This problem I was solving is more of a re-implementation of some code  I
>> had in Python. In Python, I had a very class-based structure of this
>> design. By class based structure, I mean we have class-level methods for
>> each class (where each class  is a type of Task), and all of them implement
>> the same set of methods. This classes are never instantiated, but all
>> methods are invoked on the class.
>> WIth that perspective, the record patter @Patrick recommended directly
>> maps to that design. The record data type here becomes a
>> abstract-representation of my class(abstract base class in OO terms)  and
>> each task provides its methods.  I see that relationship.  Is that the
>> approach I should be aiming for?
>> Secondly, while choosing the type-class approach,  I imagined all these
>> required class methods to be an interface and therefore an interface could
>> directly map to a type class in Haskell.  Is that thinking usually an
>> anti-pattern.
>> The existential antipattern
>> <https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/>.
>> link was very useful and made me re-asses my inclination to defining type
>> classes and embedded types right away.
>> On Tue, Feb 28, 2017 at 9:55 AM, Patrick Chilton <chpatrick at gmail.com>
>> wrote:
>>> You could also consider representing tasks like this instead of using a
>>> typeclass:
>>> data Task = Task
>>>   { process :: m ()
>>>   , canRun :: m Bool
>>>   }
>>> The Taskable + existential GADT example seems like it could be an
>>> example of the existential antipattern
>>> <https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/>
>>> .
>>> If your GADT really does have a as a type parameter, it would be more
>>> idiomatic to check for the typeclass when you use it:
>>> doStuffWithTasks :: Taskable a => Task a -> ...
>>> But then what's the point of the Task datatype?
>>> On Tue, Feb 28, 2017 at 1:48 AM, Guru Devanla <gurudev.devanla at gmail.com
>>> > wrote:
>>>> Hello All,
>>>> I am working on a program that will define a bunch of tasks. Each task
>>>> will have to implement certain methods as part of a type class.
>>>> -- task 1
>>>> data UpdateAcctsTask = UpdateAccts
>>>> -- task 2
>>>> data EmailConfig = EmaiConfig {someattrs::String}
>>>> data SendEmailTask = SendEmailsTask EmailConfig
>>>> -- task 3
>>>> data GeneralWriterTask a = GeneralWriterTask a
>>>> Each of these tasks implement a class, Taskable. The return
>>>> values are simplified for this example.
>>>> class Taskable a where
>>>>   process :: a -> Bool
>>>>   can_run :: a -> Bool
>>>> This works fine. I can expand on these tasks and execute them.
>>>> Now, I wanted to be able to defined dependencies between these
>>>> (Taskable's). I decided
>>>> I could create a data type for this dependency and may be also get a
>>>> FreeMonad
>>>> around this structure for further processing using a graph of Tasks.
>>>> But, before that I wanted
>>>> to create an wrapper for these Taskables and create a functor for it as
>>>> follows
>>>> The first thing I did was, define a Task, which generalizes over all
>>>> the above defined (and future Taskables)
>>>> data Task a where
>>>>   Task :: (Taskable a) => a -> Task a
>>>> instance Functor Task where
>>>>   fmap:: (Taskable a, Taskable b) -> (a -> b) -> Task a  -> Task b
>>>>   fmap f (Task a) = Task $ f a
>>>> But, I realized that I cannot define an fmap over a type constraint.
>>>> My questions are:
>>>> 1. Is there any way to do this. I see there is an answer of SO. I wanted
>>>>    to make sure if there were any improvements to this since that
>>>> answer'
>>>>    was posted.
>>>>    http://stackoverflow.com/questions/17157579/functor-instance
>>>> -for-a-gadt-with-type-constraint
>>>> 2. Secondly, I would like to know why this is not possible. Is it a
>>>> current
>>>>    limitation of GHC or if there is some fundamental category theory
>>>> concepts
>>>>    that dis-allows such declarations that I need to grok!
>>>> Appreciate any help on this. Thank you!
>>>> _______________________________________________
>>>> 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/20170301/d1bf5455/attachment.html>

More information about the Haskell-Cafe mailing list