Declaring Functors for Type constrained data types

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 --- THIS DOES NOT WORK 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... 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!

1. You could use MonoFunctor (complicated and probably not a good idea here) or just put the Taskable constraint on functions instead of on the Task definition (good and easy). So it would be data Task a = Task a deriving Functor And then put "Taskable a" on functions that require it. 2. You can't do it because it doesn't really make sense. A big part of a functor is that it has to be totally agnostic of what it's parametrized over. Otherwise you could easily violate the functor laws. Good question though, I used to wonder the same thing. cheers, Will
On Feb 27, 2017, at 6:48 PM, Guru Devanla
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 --- THIS DOES NOT WORK 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...
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.

Thanks, Will. I think adding the constraint to the functions is a good
idea. Plus, it makes the intent clearer at the function level.
On Mon, Feb 27, 2017 at 6:02 PM, Will Yager
1. You could use MonoFunctor (complicated and probably not a good idea here) or just put the Taskable constraint on functions instead of on the Task definition (good and easy).
So it would be
data Task a = Task a deriving Functor
And then put "Taskable a" on functions that require it.
2. You can't do it because it doesn't really make sense. A big part of a functor is that it has to be totally agnostic of what it's parametrized over. Otherwise you could easily violate the functor laws.
Good question though, I used to wonder the same thing.
cheers, Will
On Feb 27, 2017, at 6:48 PM, Guru Devanla
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 --- THIS DOES NOT WORK 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.

I've done a bit of work on a library that allows you to `fmap` say over
sets, (i.e. fmap :: Ord a, Ord b => (a -> b) -> Set a -> Set b) which is
more powerful than Monofunctor as it doesn't require the types to be the
same.
And it will involve importing a new version of "Functor" and "fmap",
however it should be largely backwards compatible.
However, it still needs a little bit of work to be in a state ready to be
uploaded to Hackage (and even then, it probably needs even more work) but
I'll give you a buzz when its up, hopefully in the next week or so.
On Tue, Feb 28, 2017 at 2:01 PM, Guru Devanla
Thanks, Will. I think adding the constraint to the functions is a good idea. Plus, it makes the intent clearer at the function level.
On Mon, Feb 27, 2017 at 6:02 PM, Will Yager
wrote: 1. You could use MonoFunctor (complicated and probably not a good idea here) or just put the Taskable constraint on functions instead of on the Task definition (good and easy).
So it would be
data Task a = Task a deriving Functor
And then put "Taskable a" on functions that require it.
2. You can't do it because it doesn't really make sense. A big part of a functor is that it has to be totally agnostic of what it's parametrized over. Otherwise you could easily violate the functor laws.
Good question though, I used to wonder the same thing.
cheers, Will
On Feb 27, 2017, at 6:48 PM, Guru Devanla
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 --- THIS DOES NOT WORK 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.
_______________________________________________ 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.

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-...
.
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
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 --- THIS DOES NOT WORK 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.

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-....
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
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-... .
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
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 --- THIS DOES NOT WORK 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.

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
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-.... 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
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-... .
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
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 --- THIS DOES NOT WORK 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.

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
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
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-.... 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
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-... .
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
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 --- THIS DOES NOT WORK 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.

But if you have for example a tree of heterogenous tasks as you said, you
can no longer dispatch based on type because the implementation depends on
the value of each task in the tree, so you're better off representing it
like this:
data Task = Task
{ doTask :: IO ()
, taskName :: String
}
class Taskable a where
toTask :: a -> Task
instance Taskable EmailConfig where
toTask (EmailConfig ...) = Task { ... }
type TaskTree = Tree Task -- easy
On Wed, Mar 1, 2017 at 3:11 PM, Guru Devanla
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
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
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-.... 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
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-... .
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@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 --- THIS DOES NOT WORK 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.

Or even:
data Task a = UpdateAcctsTask
| SendEmailTask EmailConfig
| GeneralWriterTask a
process :: Task a -> Bool
can_run :: Task a -> Bool
In general, start with data types based on the structure of your data and
functions that operate on that data. Type classes are not usually the right
abstraction for domain specific code, in my experience.
Erik
On 1 March 2017 at 15:19, Patrick Chilton
But if you have for example a tree of heterogenous tasks as you said, you can no longer dispatch based on type because the implementation depends on the value of each task in the tree, so you're better off representing it like this:
data Task = Task { doTask :: IO () , taskName :: String }
class Taskable a where toTask :: a -> Task
instance Taskable EmailConfig where toTask (EmailConfig ...) = Task { ... }
type TaskTree = Tree Task -- easy
On Wed, Mar 1, 2017 at 3:11 PM, Guru Devanla
wrote: 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
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
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-.... 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
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-... .
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@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 --- THIS DOES NOT WORK 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.
_______________________________________________ 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.
participants (5)
-
Clinton Mead
-
Erik Hesselink
-
Guru Devanla
-
Patrick Chilton
-
Will Yager