Hacker News new | past | comments | ask | show | jobs | submit login

I think this quote from the article alludes to an answer: “Somehow, the level of abstraction offered by a sophisticated type system lets you get much more ambitious in terms of the intellectual complexity of what you can deal with.”

When you have a notation well suited for using these advanced features, all of a sudden they become tractable to reason about. The languages in which AAA game engines are written have notations and semantics that are not well suited to these abstractions; and people continue to use them because they have reputations for efficiency and control that functional languages historically do not. But that’s changing with the advent of languages like Rust and ATS that bring more of the power of functional programming and advanced type system features to bear on low-level efficient code without the need for a GC. (I’m also working on such a language.)

What I’m getting at is that there are some things I do all the time in Haskell because it’s easy, which I don’t do in other languages becuase it’s hard. I know in principle how to get the same guarantees in other languages, but the expressiveness isn’t there: the encoding in the syntax & semantics of those languages is so unwieldy that I rarely bother.

Take for example something simple like algebraic data types and pattern matching. You can encode sum types with only product types (tuples/records) and functions using Boehm-Berarducci encoding, which in OOP languages is called the visitor pattern. But it takes so much more code that I often design things entirely differently to avoid it.

In Haskell I use higher-kinded polymorphism all the time—abstracting over type constructors. That’s possible to encode in C++ with template template parameters, but it’s incredibly unwieldy, produces awful error messages when you do it wrong, and can be invasive depending on what features you need to support. I use GADTs, existential types, and higher-rank polymorphism all the time, for example, passing generic functions as arguments to other functions. That’s possible to encode in OOP languages using interfaces with generic methods, but it can’t be done inline, requiring a couple of helper types and moving the “meat” of an implementation away from the actual method being defined; in Haskell I just add a “forall” with the scope I want.

So I don’t think it depends on the complexity of the program so much as the complexity of the encoding in your language of choice. It’s eminently possible to take advantage of these features in C++, Java, C#, &c. to enforce better program correctness and even gain better performance, but the “wizardry” required is not accessible to the majority of users. Whereas in Haskell, sooner or later just about everyone gains some experience with type-level programming that would be possible but prohibitively difficult to do in other languages, because Haskell was designed to support those abstractions—whether through built-in concepts, extensions, or clever combinations of orthogonal and expressive language features.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: