[Haskell-cafe] Data declaration vs type classes
Guillaume Bouchard
guillaum.bouchard+haskell at gmail.com
Mon Jan 11 14:15:34 UTC 2016
In case of the data approach, `GroceryTask` and `LaundryTask` are the
same type: `Task`. Hence you can have some kind of "dynamic"
polymorphism (or "dynamic" dispatch) by storing a list of homogeneous
types (`Task`) with heterogeneous behaviors.
For example, imagine you want to store a todo list and do all task of
the todo list.
data Task = GroceryTask | LaundryTask
doTask GroceryTask = putStrLn "grocery"
doTask LaundryTask = putStrLn "laundry"
todoList :: [Task]
todoList = [GroceryTask, LaundryTask, GroceryTask]
doAllTasks :: [Task] -> IO ()
doAllTasks tasks = mapM_ doTask tasks
However, In the case of the class approach
data GroceryTask
data LaundryTask
class Task t where
doTask :: t -> IO ()
instance Task GroceryTask where
doTask t = putStrLn "grocery"
instance Task LaundryTask where
doTask t = putSTrLn "laundry"
doAllTask :: [?????] -> IO ()
In this case, GroceryTask and LaundryTask are NOT the same type, hence
the "????", you cannot create a list which stores different Tasks and
returns apply
However you can still wrap them inside a sum type :
data DoableTask = DoableGrocery GroceryTask | DoableLaundry LaundryTask
instance Task DoableTask where
doTask (DoableGrocery t) = doTask t
doTask (DoableLaundry t) = doTask t
(Open question: is there a hack / tool / library / Template Haskell
solution to generate this kind of stuff ?)
There is other solutions, you can partially apply the doTask function,
for examples:
todoList :: [IO ()]
todoList = [doTask GroceryTask, doTask LaundryTask, doTask GroceryTask]
(Another open question, is there a simple solution to do a map over an
literal heterogeneous list to get an homogeneous one?)
Thank to laziness, this works, but can be really boring to implement.
There is other solution using existential types or heterogeneous
lists. I'm still looking for a good discussion about which one to use
when we focus on performance.
So, finally, there is no simple solution. If your type is close and
really represents a choice between a set of possibilities and that you
know you want a kind of dynamic dispatch, definitely go for the data
approach. Else, the class approach is easier to extend at the cost of
a lot of boilerplate when you want dynamic dispatch...
On Mon, Jan 11, 2016 at 12:44 PM, Lian Hung Hon <hon.lianhung at gmail.com> wrote:
> Dear all,
>
> Thanks for the opinions. I'll go with type classes for now, because as
> Miguel said, I want it to be open :)
>
> Regards,
> Hon
>
> On 8 January 2016 at 19:46, Imants Cekusins <imantc at gmail.com> wrote:
>>
>> > you convert String or Text: what encoding would you use?
>>
>> let's say, this is very specific conversion where newtypes are used a
>> lot. There are many different formats for Int (even the same type of
>> int), String may be ascii, UTF8, ISO-..., you name it.
>>
>> using class does not make a difference re: type definition in this case.
>> _______________________________________________
>> Haskell-Cafe mailing list
>> Haskell-Cafe at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
>
More information about the Haskell-Cafe
mailing list