Hot answers tagged

230

Here's an unordered list of type system features available in Haskell and either unavailable or less nice in Java (to my knowledge, which is admittedly weak w.r.t. Java) Safety. Haskell's types have pretty good "type safety" properties. This is pretty specific, but it essentially means that values at some type cannot wantonly transform into another type. ...


138

The actual pattern is actually significantly more general than just data access. It's a lightweight way of creating a domain-specific language that gives you an AST, and then having one or more interpreters to "execute" the AST however you like. The free monad part is just a handy way to get an AST that you can assemble using Haskell's standard monad ...


78

Full type inference. You can actually use complex types ubiquitously without feeling like, "Holy crap, all I ever do is write type signatures." Types are fully algebraic, which makes it very easy to express some complex ideas. Haskell has type classes, which are sort of like interfaces, except you don't have to put all the implementations for one type in ...


63

("Java", as used here, is defined as standard Java SE 7; "Haskell", as used here, is defined as standard Haskell 2010.) Things that Java's type system has but that Haskell's doesn't: nominal subtype polymorphism partial runtime type information Things that Haskell's type system has but that Java's doesn't: bounded ad-hoc polymorphism gives rise to "...


62

a :: Integer b :: Maybe Integer c :: IO Integer d :: Either String Integer In Haskell: an integer, an integer that might be null, an integer whose value came from the outside world, and an integer that might be a string instead, are all distinct types - and the compiler will enforce this. You cannot compile a Haskell program which fails to respect these ...


61

A lot of the answers are going into things like infinite lists and performance gains from unevaluated parts of the computation, but this is missing the larger motivation for laziness: modularity. The classic argument is laid out in the much-cited paper "Why Functional Programming Matters" (PDF link) by John Hughes. The key example in that paper (Section 5) ...


48

A few downsides I can think of: Due to the language's nature and its firm roots in the academic world, the community is very math-minded; if you're a pragmatic person, this can be overwhelming at times, and if you don't speak the jargon, you'll have a harder time than with many other languages. While there is an incredible wealth of libraries, documentation ...


45

The closest equivalent to looping over an array in most functional languages is a fold function, i.e. a function that calls a user-specified function for each value of the array, passing an accumulated value along the chain. In many functional languages, fold is augmented by a variety of additional functions that provide extra features, including the option ...


42

I realize I'm coming late to the party, but you've had two theoretical answers here, and I wanted to provide a practical alternative to chew over. I'm coming at this as a relative Haskell noob who nonetheless has been recently force-marched through the subject of Arrows for a project I'm currently working on. First, you can productively solve most problems ...


42

There is an easy, but boilerplate heavy way to seal classes in Java. You put a private constructor in the base class then make subclasses inner classes of it. public abstract class List<A> { // private constructor is uncallable by any sublclasses except inner classes private List() { } public static final class Nil<A> extends List&...


41

Well, BASIC had LET for assignment as part of the syntax from the start in 1964, so that would predate the use of let in Lisp, which as Chris Jester-Young points out didn't appear until the 1970s according to Evolution of Lisp. I don't believe COBOL, Fortran, or ALGOL have LET in their syntax either. So I'm going to go with BASIC.


37

I actually think that return type polymorphism is one of the best features of type classes. After having used it for a while, it is sometimes hard for me to go back to OOP style modeling where I don't have it. Consider the encoding of algebra. In Haskell we have a type class Monoid (ignoring mconcat) class Monoid a where mempty :: a mappend :: a -...


37

It is very much like learning math will improve your analytic skills and learning latin/classic literature will improve your writing skills. People who designed those languages have thought hard about what does writing a program means. And those languages are the results of those researches. That said, learning Java will also make you a better programmer. ...


35

The Hindley-Milner type inference is used for Hindley-Milner type systems, a restriction of System-F type systems. The interesting feature of HM type systems is that they have parametric polymorphism (aka. generics). That is the single biggest type system feature that Golang refuses to have. With that frustrating restriction, HM-style type inference is ...


34

AFAIK, GCC use hand-written parsers in particular to improve syntactic error diagnostics (i.e. giving human meaningful messages on syntax errors). Parsing theory (and the parsing generators descending from it) is mostly about recognizing and parsing a correct input phrase. But we expect from compilers that they give a meaningful error message (and that they ...


34

I'll give a short answer due to my lack of time at the moment, but I'm currently working on two big projects (> 100.000 LOC in Haskell) - flowbox.io and luna-lang.org. We use Haskell for all the parts, including the backend, compiler of our programming language and even the webGL based GUI. I have to admit that the strong type system and the "dependent type"-...


33

Views #1 and #2 are incorrect in general. Any data-type of kind * -> * can work as a label, monads are much more than that. (With the exception of the IO monad) computations within a monad are not impure. They simply represent computations that we perceive as having side effects, but they're pure. Both these misunderstandings come from focusing on the ...


33

The problem with IO a = worldState -> (a, worldState) is that if this were true then we could prove that forever (putStrLn "Hello") :: IO a and undefined :: IO a are equal. Here is the proof courtesy of dolio (2010, irc): forever m = m >> forever m = fix (\r -> m >> r) = {definition of >> for worldState -> (a, worldState)} fix ...


33

You could easily convert it to recursion. And it has nice tail-optimized recursive call. Pseudocode : public int doSomeCalc(int[] array) { return doSomeCalcInner(array, 0); } public int doSomeCalcInner(int[] array, int answer) { if (array is empty) return answer; // not sure how to efficiently implement head/tails array split in clojure ...


32

How can this paradigm be used to build predictable software that works as intended, when we have no guarantee when and where an expression will be evaluated? When an expression is side-effect free, the order in which the expressions are evaluated does not affect their value, so the behavior of the program is not affected by the order. So the behavior is ...


32

Java's type system lacks higher kinded polymorphism; Haskell's type system has it. In other words: in Java, type constructors can abstract over types, but not over type constructors, whereas in Haskell, type constructors can abstract over type constructors as well as types. In English: in Java a generic can't take in another generic type and parameterize ...


32

Alright, first rule of error handling in Haskell: Never use error. It's just terrible in every way. It exists purely as an act of history and the fact that Prelude uses it is terrible. Don't use it. The only conceivable time you could use it is when something is so internally terrible that something must be wrong with the very fabric of reality, thus ...


32

To expand on @KarlBielefeldt's answer, here's a full example of how to implement Vectors - lists with a statically-known number of elements - in Haskell. Hold on to your hat... {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveTraversable #-} {-# LANGUAGE ...


30

I'd like to add a theoretical point of view: In classical lambda calculi, let is just syntactic sugar. For example let x = N in M can be rewritten simply as (λx.M)N So its first appearance in early (functional) languages isn't that interesting. However, it become very important with the invention of Hindley-Milner type system and its type inference ...


30

Lots of people have listed good things about Haskell. But in answer to your specific question "why does the type system make programs more correct?", I suspect the answer is "parametric polymorphism". Consider the following Haskell function: foobar :: x -> y -> y There is literally only one possible way to implement this function. Just by the type ...


30

No. Pretty much all modern programs use more space than is necessary. If your Java program is keeping objects alive when the programmer thinks it should be eligible for collection, it is a memory leak. It is a common, well known term. Yes, it will vary a bit by context, but the underlying concept is close enough that the mental jump is very short. ...


29

This is kind of a "soft" answer, and I'm not sure if any reference actually states it in this manner, but this is how I've come to think of arrows: An arrow type A b c is basically a function b -> c but with more structure in the same way that a monadic value M a has more structure than a plain old a. Now what that extra structure happens to be depends ...


29

Haskell syntax is close to human language. It is specifically designed to resemble mathematical notation, which is a language designed by humans (thus a human language) to express precisely those concepts that Haskell is built upon. You can show a piece of Haskell code to any mathematician or logician, and he will be able to understand it, even if he has ...


26

For the purposes of this answer I define "purely functional language" to mean a functional language in which functions are referentially transparent, i.e. calling the same function multiple times with the same arguments will always produce the same results. This is, I believe, the usual definition of a purely functional language. Pure functional ...


25

According the Great Benchmarks Game, ATS is faster than the rest with Haskell, Scala, and one of the variants of Common Lisp in a rough tie for speed close behind that. After that Ocaml and F# are in roughly the same speed category with Racket and Clojure lagging behind... However, almost none of this means anything at all really. It's all a question of ...


Only top voted, non community-wiki answers of a minimum length are eligible