A few of my favorites include: first-class functions, algebraic data types and opaque data types.
First-class functions
Because of all the cool abstractions — map
, filter
, accumulate
, 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
And you?