Because of all the cool abstractions —
fold etc — you can build with them.
(define (map f l) (if (null? l) '() (cons (f (car l)) (map f (cdr l)))))
Algebraic data types
Especially sum types. I think all languages should support this feature. They make it really convenient to precisely model your domain.
Ruling out invalid data makes your code shorter, simpler, and more reliable. By making sure the set of possible values in code exactly matches the set of valid values in real life, many problems just go away. — Types as Sets
type RemoteData e a = NotAsked | Loading | Failure e | Success a
Opaque data types
Data abstraction allows you to hide implementation details and it makes it favorable to change representations. For e.g. you can start with a naive implementation and change to a more efficient representation if it proves critical to the overall performance of the system. Opaque data types are frequently used to implement abstract data types.
module Stack ( Stack , empty, push, pop ) where data Stack a = Empty | Stk a (Stack a) empty :: Stack a empty = Empty push :: a -> Stack a -> Stack a push x s = Stk x s pop :: Stack a -> Stack a pop Empty = Empty pop (Stk _ s) = s