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@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@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@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe