Anybody using this? In production or otherwise? I've been using it for a few months now and I am continually floored not just by the language but also the quality of code and abstractions that the community produces. The community tends to draw inspiration from category theory, a branch of mathematics considered to be esoteric, but leads to abstractions which are elegant and generate properties and assurances which have already been 'proven' correct by the mathematicians. For instance, an implementation of Functor which satisfies the functor laws (fmap id == id, fmap f . fmap g == fmap f . g) will do 'the right thing' when used: if you think of a functor implementation as a container containing things of type a, fmap f will change just the a's in the container and nothing about the structure of the container. Two popular examples are of this are List and Maybe. Code: data Maybe a = Just a | Nothing data List a = Cons a (List a) | Nil These correspond roughly to the C++ types Code: enum MaybeTag { Just, Nothing }; template<T> struct just { // insert boilerplate constructors T *data; } struct nothing { }; template<T> { struct maybe { // insert boilerplate constructors MaybeTag tag; union { struct just *casejust; struct nothing *casenothing; } data; }; enum ListState { Cons, Nil }; template <T> struct cons { // insert boilerplate constructors T *data; struct list<T> *next; }; struct nil { }; template <T> struct list { ListTag tag; // insert boilerplate constructors union { struct cons *casecons; struct nil *casenil; } data; }; /* * In performant list implementations, this data is typically compressed to: * template<T> struct list { * T *data; * struct list *next; * }; * Here, whether *next is a null pointer or not tells us which state we are in. */ That's a lot more verbose, eh? fmap is defined as follows: Code: -- a function taking a function taking a's to b's, and returns a function taking Maybe a's to fmap :: (a -> b) -> Maybe a -> Maybe b Maybe b's fmap f (Just x) = Just (f x) fmap f Nothing = Nothing fmap :: (a -> b) -> List a -> List b fmap f (Cons x xs) = Cons (f x) (fmap f xs) fmap f (Nil) = Nil Again, corresponding the (much more verbose) C++ code. (This is just for illustration purposes so some of the syntax may be imprecise). Code: // for reusability, fmap should define an interface which list and maybe inherit from. template<A,B> struct maybe<B> *fmap(struct maybe<A> *m, function<A*,B*> f) { switch (m->tag) { case (Nothing) : { // let's hope new is overloaded to allocate in a memory managed pool ;) return new maybe<B>(Nothing); } case (Just) : { return new maybe<B>(Just, f.apply(m->casejust->data)); // f.apply returns a newly allocated struct just. } } } template<A,B> struct list<B> *fmap(struct list<A> *l, function<A*,B*> f) { switch (l->tag) { case (Nil) : { return new list<B>(Nil); } case (Cons) : { return new list<B>(Cons, f.apply(l->caselist->data), fmap(l->caselist->next)); } } } I didn't really intend for this to become a tutorial so I'll cut to the point. You can easily see that fmap applied to a Just will return a Just, and applied to a Nothing will return a Nothing. Likewise, fmap applied to a Cons will return a Cons, and fmap applied to a Nil will return a Nil. In fact, fmap f l will return a list of the same length as the input, and it will simply be a list containing the results of applying f to all the elements in the input. So, by inspection, fmap is structure preserving. Maybe and List have pretty trivial structure so you may be like, so what? this is obvious. Amazingly, this structure-preserving property is actually guaranteed by the mathematicians from the fact that fmap obeys the two functor laws: Code: fmap id (Just x) = Just (id x) == Just x (fmap f . fmap g) (Just x) = fmap f (fmap g (Just x)) = fmap f (Just (g x)) = Just (f (g x)) == Just ((f . g) x) fmap id (Nothing) = Nothing == Nothing (fmap f . fmap g) (Nothing) = fmap f (fmap g Nothing) = fmap f Nothing == Nothing The proof for list is similar but involves recursion. This structure-preserving property is helpful for designing large systems because you could be coding up against an arbitrarily complex system, and as long as you trust that it implemented the fmap interface correctly, you can perform arbitrary operations on items of interest contained in the system, and have an assurance that the rest of the system will be untouched. In practical terms you won't introduce unintended breakage. For more reading I recommend the following: http://www.haskellforall.com/2012/08/the-category-design-pattern.html http://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/ Anyways I am interested in people's experiences (whether good or bad) using Haskell for production. I realize the Haskell runtime may not be appropriate for real-time requirements i.e. core trading engine, so I'm interested also in experiences using it for supporting tasks: analysis, report generation, sysadmin, monitoring, etc. Do people view it as 'a better mousetrap' or a nice 'theoretical language' that doesn't do much? Please, let's keep this converstion civil and on-topic. I don't want it devolving into another flame war. @nitro @monoid
Great post. The only place I have come in touch with Haskell was when I needed to extend some functionality of an open source message bus that is implemented in Haskell. Despite its elegance I believe it lends itself only to very narrowly defined projects because there are hardly any open source libraries or projects in the public domain that can be perused. I guess common sense applies here as well: Use whatever tool works best for a specific problem. I think using Haskell to implement, for example, an algorithmic trading framework will prove very ill advised.
Thanks, regarding the Haskell ecosystem not being as extensive as, say, python or Java or C#, there are still a lot of high quality packages in different domains which you can peruse at http://hackage.haskell.org/packages/ I guess I'm interested, in general what tools would you want to see associated with a language/framework before you selected it to use in production?
This is not recommendation since I did not read it yet but I have found it searching financial books: Haskell Financial Data Modeling and Predictive Analytics Paperback – October 25, 2013 (on Amazon by Pact Publishing)
Something like python pandas Erlang likemessage passing and supervision a repl Examples found on Google or stackoverflow
I would require a broad based user acceptance and libraries that support, to just name a few examples: * Async programming ability, automatic but customizable thread/task handling * message bus libraries * math/stats/probability libraries * data flow libraries (to manage various kinds of data flow, branching out, joining data streams, ....) * serialization/deserialization libraries * how to hook into other OOP language based APIs * various collections (thread safe, or concurrent) Edit: Found some libraries that offer parts of the above but not all...
I checked briefly Haskell and my impression is that it is more a religion than programming language. Whatever it does has been done before. It has to be programmed itself in another programming language (C) with multiple steps between Haskell code and the runtime meaning slower execution and more points of potential failure and errors.
Just a joke, F# has all the things you listed, but Haskell/OCaml zealots usually deride it for not being 'pure' enough.