
The Story of Haskell at IMVU - adamnemecek
https://chadaustin.me/2016/06/the-story-of-haskell-at-imvu/
======
chadaustin
Hi! Author here. Let me know if you have any questions.

Andy, the same Andy mentioned in the article, wrote a blog post in 2014 with
his perspective of what it's like to use Haskell in production, if you're
interested. [https://engineering.imvu.com/2014/03/24/what-its-like-to-
use...](https://engineering.imvu.com/2014/03/24/what-its-like-to-use-haskell/)

~~~
rakpol
Hoping for a little advice: I'm trying to push for some development culture
changes at work, one of which is doing more local, incremental refactors
rather than large, all-at-once changes (i.e. the sort of thing for which one
books 'architecture meetings'). Since we'll hopefully be massaging large parts
of the codebase, there's an opportunity to jump into something new with both
feet.

Question: what do you think of the thesis of pure4j [1] vis. frege [2]?
Namely, are the advantages gained by switching to a haskell-like language far
above those attained by simply forcing effects into a small part of the
codebase?

[1]: [https://github.com/pure4j/pure4j](https://github.com/pure4j/pure4j)

[2]: [https://github.com/Frege/frege](https://github.com/Frege/frege)

~~~
Buttons840
Scala is an obvious option as well. I haven't used Scala but it's surely more
palatable to Haskellers than plain Java.

Also. There is work underway to enable GHC to compile for the JVM.

~~~
wtracy
To expand on this suggestion: Scala isn't big on purity (AFAIK the language
has no concept of pure functions out of the box) but it is big on immutable
data types, and mostly-pure functions arise naturally when you're working with
immutable types.

Immutable types happen to be something that _is_ familiar and comfortable to
Java developers. I would therefore expect to meet a lot less resistance to
"syntactic sugar and immutable classes" than "functional programming with pure
functions" even if the end result is 80 percent the same.

~~~
roflc0ptic
This was the compromise our team made. Our team was having a bad time dealing
with Spring. Our lead dev is a functional buff who really likes Haskell, and
got us all hype about trying something new. We picked scala in lieu of Haskell
because the learning curve with Haskell was a much harder sell. We avoid
mutable data types unless there's a compelling reason (interop with Java
libraries, for example), and most of our functions are implicitly pure. ScalaZ
might have some purity constraint, idk.

5 months in with Scala and it has been a wonderful experience. Now I just have
to convince our front end dev to switch over to Scala.js...

~~~
MustardTiger
We tried the same thing, but it did not go well at all. We picked scala
because people should be able to learn it easier and more gradually. But we
found as people learned FP using scala, they realized how much scala held them
back. We ended up redoing a PHP project in scala, then as it was 80% done
redoing it again in haskell. And then from there out using haskell for
everything.

~~~
roflc0ptic
Do you have any specific examples of how scala would hold y'all back in
relation to haskell? I actually have trouble imagining how one could justify,
in a business, scrapping an 80% complete rewrite to rewrite it again in a
different language. I wonder what would be so compelling.

~~~
MustardTiger
Scala is an OO language with FP tacked on, so it basically defaults to "make
everything a pain". It was easy to justify rewriting it again because it only
took two weeks to do it. A re-write is much faster than initially writing it,
you're just copying yourself.

~~~
premium-concern
I wonder why Haskell people feel so hurt about Scala...

It's much closer to Haskell's capabilities than pretty much any other
functional language.

It has better type classes, the compiler just got type inference for partially
applied type constructors, it supports programming with dependent types and
implicit parameters allow you to let the compiler prove almost arbitrary
things.

If your definition of FP means "purity", you pretty much discarded all
languages traditionally considered to be functional.

There is nothing wrong with liking Haskell more than Scala, but I think your
claims are not very well-founded.

~~~
kmiroslav
> It has better type classes

Haskell and Scala win and lose on different criteria but for type classes, I
find Haskell's syntax and semantics infinitely more elegant, more terse and
more flexible than Scala's. Defining type classes in Scala is a cacophony of
syntax boiler plate riddled with implicits and brackets. Haskell is much more
elegant in that area.

~~~
premium-concern
Scala's typeclasses are first-class values and they actually work as
advertised.

Haskell's type classes are a mess because Haskell-the-spec (anti-modular,
coherent) and Haskell-the-language (incoherent, "modular") work completely
different and nobody cares and there us no real fix because both options suck,
as soon as your project consists of more than one module.

It's the reason why no language after Haskell does type classes the Haskell
way, and all of them do it similar to Scala's approach.

Could Scala have more syntax sugar? Sure! But people are more focused on
getting them right first, before adding additional syntax.

~~~
MustardTiger
What on earth are you talking about? Tons of other languages do type classes
"the haskell way". Which is also known as "type classes". Scala doesn't have
type classes, it has a close approximation.

~~~
codygman
What other languages do type classes like Haskell?

~~~
MustardTiger
All of them? Who else has broken almost like typeclasses other than scala?

~~~
codygman
All of the languages? Go doesn't have them. Neither does C.

~~~
MustardTiger
Obviously, all of the languages with type classes. Those languages do not have
"type classes" like scala does, which is what I was replying to.

~~~
premium-concern
So basically what you are saying is "Haskell has Haskell's typeclasses!".

That's a yuuuuge amount of languages that follow "Haskell"'s design! (Maybe
you should start counting Haskell-to-X compilers separately to pad the number
"1" a bit?)

~~~
MustardTiger
Please read the posting guidelines and contribute constructively or not at
all.

~~~
premium-concern
I have already mentioned three languages that haven't followed Haskell's
broken mess, while you have failed to produce even a single bit of
information, while constantly crying foul at everything you don't like?

That's just amazingly hypocritical, but I guess the tactic of "blame other
people for your own behaviour to make it look like tu-quoque if they respond"
hasn't gotten old for you yet?

~~~
MustardTiger
I did not read your responses to other people, since you are obviously
trolling. Your three examples are nonsense, two are haskell style, and one
doesn't have type classes at all (ocaml).

~~~
premium-concern
Ok, so if I understand you correctly: you claim that your failure to
contribute anything of substance should be blamed on your inability to read
and your lack of any knowledge of the topic.

Well enough, sir.

------
ayberkt
It makes me sad how people think imperative programming is a "natural" way to
think. I have known lots of people who resist using functional languages for
serious projects, marginalizing the "functional" way of thinking as though
thinking in terms of "labeled boxes with data in them" (Von Neumann
architecture) is some sort of more normal way to think.

Before computers people modeled the real world using a Haskell-like pseudocode
called "mathematics".

~~~
chadaustin
I find both mental models useful. For example, "accumulate all of the monoids
in this collection"
([https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-F...](https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-
Foldable.html#v:msum)) makes total sense as a functional operation. You have a
collection and some pure operations you want to apply to combine it all into
one thing.

But then, sometimes you just want to iterate across a list of directories,
read some files, and put some results in lists. Tail-recursion here feels
dumb. Like, dammit, I'm the human and you're the computer, I know you can turn
a sequence of instructions into a tail recursive loop for me, so don't make me
think.

Haskell, due to its effectful / monadic vs. pure syntax distinction isn't
terribly great here. Ideally I'd write all of my code in an "imperative style"
all the time, but a row-typed effect inference system would determine which
functions were pure, or in IO, or async, or in ST, or threw exceptions, etc.
Koka [1] is an interesting language that explores some of these ideas.

[1] [http://research.microsoft.com/en-
us/projects/koka/](http://research.microsoft.com/en-us/projects/koka/)

~~~
daxfohl
Agreed, I just recently took some recursive F# code from a photobooth (display
countdown, async sleep, take photo, download from camera, recur with new
byte[] list)->reverse list, and rewrote it it an imperative loop appending to
a normal List<byte[]> and the code is much more intuitive.

Some things are more intuitive as a list of things to do and changes to make.

~~~
lgas
Aren't IO Actions just a list of things to do and changes to make? I'm asking
genuinely to try to understand the difference.

~~~
daxfohl
Yes they are, but I think "for loops" and "mutable lists" a'la Java's
ArrayList and Vector and C#'s List<T> don't exist even in IO (I'm not a
Haskell expert). That kind of thing has to be done with recursion. They exist
in F# but are not idiomatic. However sometimes they're more intuitive (to me
at least).

~~~
acomar
forM is a for each loop over anything iterable (Traversable in Haskell) that
will execute a given monadic action on each element in the collection. A more
traditional for loop is this over a range of integers or whatever else you
feel like.

    
    
        forM (range 5) println
    

Mutable collections exist in various forms depending on what kind of
mutability you want. For example, there's transactional mutability that gives
you mutable data structures inside an STM but forbids IO. And there's IO
mutability that removes all the bounds but restricts you to the IO Monad.
TVars, MVars, and the various kinds of Refs are what you're looking for here.

~~~
jbooth
If someone is asking for mutability for reasons of performance and clarity,
giving them STM is like a kick in the teeth.

~~~
codygman
How is STM like a kick in the teeth? In performance? How? In clarity? How?

Can you give examples of STM being a kick in the teeth versus mutability.

~~~
carterschonwald
I suspect he didn't keep the size of his stm atomically programs small. The
docs and associated papers and book materials all make it very very clear that
you want to keep stm transactions small and try to defer computation into
thinks that are only evaluated when the transaction succeeds.

~~~
jbooth
Compare the cost of optimally, expertly built STM-using code to, say, just
assigning some byte values in a *char array. Instruction count? Cache
locality? Allocations?!?

EDIT: Oh, and isn't STM typically just a wrapper over immutable stuff anyways?
So he said "immutable copying is too slow for me", and you said "here, use
this instead, it has all the copy overhead plus some additional overhead"..
that's a kick in the teeth.

~~~
15155
> Compare the cost of optimally, expertly built STM-using code to, say, just
> assigning some byte values in a *char array

This is comparing the wrong tasks. Apples and oranges.

STM is usable for this particular task, but will almost assuredly be far
slower. If performing the exact same task in Haskell, you could use IO and
mutable memory for comparison.

Where STM really shines, however, is in highly-concurrent environments.
There's no great "C comparison" for hundreds of concurrent operations
locklessly reading/writing to/from the same memory. STM makes this safe and
performant without a change in semantics or additional mental overhead from
the "non-concurrent" case.

~~~
jbooth
I'd limit your case to "highly-concurrent environments where want lots of
shared, mutable state". There's always cases for some shared or global thing
that you're transacting with, but I think 99% of code in highly-concurrent
environments should be written with message-passing and limited scope at any
point in the program.

------
dhab
I have programmed in Java for some time now, and I have only recently dabbled
in the functional world (Haskell, and still ways to go before getting any
better in it). My observations about it is that functional programming in
typed and immutable world, provide better composability, reusability,
terseness and maintainability. It does have it's drawbacks - Haskell is known
to be difficult for estimating complexity, and i think it lags in many
benchmarks.

I think OO can be thought of as an extension of functional programming, except
it has some fancy names and idioms (single responsibility principle,
polymorphism, abstractions ... ), but in the end are incarnations of
functions. For example, int String.length(){..} could be thought of as
length(char[]):int function, and List.size() as length(List):int. Node
Tree.next(DepthFirstStrategy) could be thought of as traverse(Tree,
traversalFunction):Node. But because OO languages tend to be mutable, they
lose the benefits of the FP world. However, because they are mutable, they
tend to perform better in benchmarks. I think OOP implemented in an immutable
language would be over-engineered FP, whereas OOP implemented in mutable
language is just glorified imperative programming.

With my experience so far learning functional programming, I think it is a
better tool: All the things you can do in OO world, you can also do in FP
world, mostly better. When performance is of real concern, then those bits
could be factored out into some imperative code - whether it's done in OOP or
assembly, C is a matter of choice.

In other words, I think in the order of technology preferences, FP should be
prioritized higher than others although there seems to be a steeper learning
curve. I think FP is not getting the attention it deserves as a better tool.

------
douche
Interesting, especially about the cultural division and politics.

Something to think about, since I'm thinking of swapping out some problematic
C# code for F#. Pattern matching and a stronger, more expressive type system
would be very nice. F# isn't as far off the reservation as Haskell, but I'm
not sure how well throwing a monkey wrench, at the team will go.

~~~
louthy
Moving from C# to F# is much less politically difficult than moving to
Haskell. For a start the framework they're on is the same, and actually, you
can write object oriented F# that looks almost the same as C# (not that I
would advise that, I prefer to use the OO side of F# as a last resort).

I'm the CTO at my place of work, and our primary app is C#. I wanted to tame
some of the excesses of the language, and started looking at Haskell - I
knocked up a few small projects with it; got it talking to the C# app through
RabbitMQ, all happy days. But a few months later I came back to the projects
to find they had rotted because of cabal. Some projects I found it next to
impossible to recover. That left a pretty sour taste, which was gutting
because I loved the language.

Then I took a look at F#. It's not as impressive as Haskell as a language, but
it really does sit in that sweet spot for 'fitting in' to a big project
environment. I've found that creating satellite projects to our core app in F#
has been the perfect way to go. It's moved the team into that mindset slowly
without having to force the issue.

~~~
douche
> I've found that creating satellite projects to our core app in F# has been
> the perfect way to go

Can you elaborate on how that is laid out? I've identified some existing C#
code in various of our current projects that could benefit from conversion to
F#, but I'm not sure how the resulting projects should be structured.

~~~
louthy
Some things are just projects in the main VS solution. So for example I wanted
to create a document search system. So I created an F# project in the main
solution, brought in Lucene.NET from nuget. Half an hour later, done. You can
call the functions in F# directly from C#. There are sometimes some type
interop issues to deal with, but mostly it's painless.

Other projects are separate microservices that talk to our main app through my
messaging framework [1]. It's an actor-model that I built a C# and F# API for,
and they communicate via Redis. But tbh you can use anything you like: make it
RESTful, use WebServices, RabbitMQ, etc. The great thing is you have access to
the same libraries on both languages.

If you're thinking of refactoring existing projects then you could go the
mechanical route of just converting classes like-for-like. But you miss out on
some of the amazing type system benefits of F# if you do that.

What I tend to do is design all of the types first, as records or
discriminated unions. A bit like if you were doing a DB related project you
might spend some time designing the schema first, thinking about how the data
should be laid out. With ADTs you can design the states of your application,
whatever it is, and then you write the functions that transform those states
in a referentially transparent way.

Then you book-end your lovely functional code with the IO.

This whole process is much simpler when you start with smaller services; so if
you've found sections of your existing app that you want to break out, then
that's perfect.

By the way, if you want some of the functional niceness in C# too, then check
my library below. It was built with your situation in mind (because it's mine
too). It also has some utility functions for F#/C# interop.

[1] [https://github.com/louthy/language-
ext](https://github.com/louthy/language-ext)

~~~
douche
Thank you, that is a very nice summary of the design process. I'll be keeping
it in mind as I think about my Skype for Business Online UCWA wrapper later
this week..,

~~~
louthy
My pleasure :)

fsharpforfunandprofit.com is always a good place for general advice on this:

[https://fsharpforfunandprofit.com/posts/porting-to-csharp-
in...](https://fsharpforfunandprofit.com/posts/porting-to-csharp-intro/)

~~~
douche
Yeah, that's quite a resource, I've been reading through their stuff a lot
lately

------
kmiroslav
It's refreshing and uncommon to see someone who sees value in PHP, Java and
Haskell at the same time.

Nice to see open mindedness about languages for a change.

~~~
MustardTiger
Where are you seeing that? "PHP was not usable" doesn't sound like seeing
value in it.

~~~
yawaramin
The value was it came with less drama among his colleagues.

~~~
MustardTiger
That isn't seeing value in PHP. That is stating that he values things other
than language enough to use something he finds terrible.

------
cmrx64
Great read. I love it when oral history in our field gets recorded. One of my
great fears is that more interesting stories than not will be lost to time.

------
todd8
I like Haskell, perhaps because of my strong mathematics background. My
dilemma is should I spend more time developing my Haskell skills or should I
spend some time with the new C++ features, or learning Rust, or just
programming in the languages that I am already productive in?

When I assess a programming language, one of the questions I ask myself is
"How will this programming language help me write correct programs?" In more
detail I want a language that helps with four goals related to the ability to
produce programs that achieve their specifications:

(1) Partial correctness: the program doesn't give wrong answers

(2) Total correctness: the program does (1) and doesn't deadlock or get stuck
in an infinite loop. It eventually produces a correct answer.

(3) The program does (2) within the desired performance bounds specified.

(4) The program does (3) while making efficient use of hardware.

Haskell definitely helps with (1). Reasoning about the partial correctness of
Haskell programs is easier than it is with imperative programming languages.
Total correctness is _very_ hard, especially with multi-thread, multi-process,
or multi processor programs, but I think that Haskell is helpful here as well.

The real problem is that Haskell makes (3) and (4) very difficult to
understand. Some of this is that compilers for functional programming
languages are magic, making it hard to reason about what they are doing. This
is further aggravated by Haskell's non-strictness.

A discouraging look at Haskell: "Why Is Haskell Used So Little In The
Industry"[1] and "Disadvantages of Purely Functional Programming"[2]

[1] [http://flyingfrogblog.blogspot.co.uk/2010/05/why-is-
haskell-...](http://flyingfrogblog.blogspot.co.uk/2010/05/why-is-haskell-used-
so-little-in.html)

[2]
[http://flyingfrogblog.blogspot.co.uk/2016/05/disadvantages-o...](http://flyingfrogblog.blogspot.co.uk/2016/05/disadvantages-
of-purely-functional.html)

~~~
seagreen

      Citing Credit Suisse and Standard Chartered is just 
      name-dropping big banks in the hope that it will deceive 
      people into thinking that these institutes are seriously 
      invested in Haskell. They are not.
    

Lol, Standard Chartered is hiring like 30 haskellers _this year_, and I'm
pretty sure they were heavily invested in Haskell in 2010. That writer of that
article has an axe to grind, and is twisting facts to suit it.

~~~
seagreen
Update: sorry you're getting downvoted, that's not me. I think worrying about
the predictability of performance is perfectly reasonable, especially in the
presence of lazy evaluation.

------
SkyMarshal
So Haskell got you all of the following:

* GHC’s support for safe concurrent programming is world-class

* Sound type safety led to refactoring being a breeze

* Fun, stretches the mind (for some people)

* Perfectly reliable unit tests.

* Concurrent batched IO.

* Abstractions for things like timeouts and running tasks on other threads while correctly bubbling failures.

* Fantastic support for safely encoding and decoding JSON.

* One of the best benchmarking tools I’ve ever used.

And the complaints amounted to:

* Devs have to think more about which String representation to use

* Devs have to think more about syntactical differences from the more familiar C-derived languages

* The team has to support more backend platforms, duplicate infrastructure

* Not a mainstream language (harder to learn, hire for, bus factor)

* “at this stage in my career I don’t want another programming language”

75% were for and 25% were against. Frankly the only complaints worthy of
serious response were infrastructure duplication and hiring/skill
development/bus factor. The rest are people just being close-minded and lazy.

------
mmbaghdad
Nice read, you encouraged me to give haskell another round.

------
wyager
Good read! We've had a few good "haskell in production" articles recently.
Hopefully this encourages some folks to try it.

