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.
These correspond roughly to the C++ types
That's a lot more verbose, eh? fmap is defined as follows:
Again, corresponding the (much more verbose) C++ code. (This is just for illustration purposes so some of the syntax may be imprecise).
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:
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
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
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