It depends on who you ask. Academically speaking, functional programming is a declarative programming paradigm more closely related to mathematics. Emphasizing pure functions over objects; transformations over instructions; and recursion over looping,
Pure functions lack side-effects (behaviour unrelated to the output). Meaning that, a pure function's input will always receive the same corresponding output. Naturally, this implies the absence of state. Some functional programming languages are more strict about this than others. For example, Clojure allows impure functions and comes with constructs for creating and managing state. Unlike Clojure, Haskell does not allow impure functions. It emulates side-effects by using a construct called a monad to create real-world programs.
I like to think of functional programming programs as a series of transformations on data. This contrasts with imperative or object-oriented programming programs where a program can be classically thought of a series of instructions for the computer to execute. We can achieve a series of transformations by using recursion and higher-order functions. All functions in functional programming languages are first class, meaning that can be passed as arguments and returned by other functions just like any other datum in your program. Now we can create a function to apply a function to every element in a list, it's called
(defn map "Recursively applies `f` to each element in `coll`, returning the new collection." [f coll] (let [[head & tail] coll] (if (empty? coll) nil (cons (f head) (map f tail))))) ;; the identity function returns it's argument user> (map identity (range 10)) (0 1 2 3 4 5 6 7 8 9) ;; the inc function increments an integer user> (map inc (range 10)) (1 2 3 4 5 6 7 8 9 10)
Similarly we could apply the same concept, instead of passing a function, we can pass a predicate (function that returns a boolean value), and return all the values that satisfy the predicate. We call this filter:
(defn filter "Recursively applies `f` to each element in the collection, returning a new collection of all the elements where `f` returned true." [f coll] (let [[head & tail] coll] (if (empty? coll) nil (if (f head) (cons head (filter f tail)) (filter f tail))))) user> (filter even? '(0 1 2 3 4 5 6 7 8 9)) (0 2 4 6 8)
Functions like map and filter are called reducers. By chaining together reducers, we can create functional programs that are a series of transformations on data. Don't worry though, most functional programming languages come with many robust reducer out-of-the-box, so it's rare you'll have to write your own.