Describe what to do by naming and composing procedures, instead of how to do it by a writing down a step-by-step sequence of statements with all the irrelevant details.

"A circle is the locus of all points equidistant from a given point." versus "To construct a circle, rotate a compass with one arm fixed until the other arm has returned to its starting point."

The idea is to define a concept of a circle and use it in a higher-level language, while "implementation details" are kept below the level of abstraction. The canonical example is List Comprehensions where we express that we are traversing a sequence, keeping the actual code outside the scope. Python takes comprehensions and generalizing of collections via iterators and generators to a next level. So does Scala

The related idea is macro-expansion. We could define a macro which describes an action which expands into the actual code which performs it.

The above principle applies not only to programming, but in a much broader sense to the human communication in general - we use names as references to shared concepts and mental constructs.

## Grounded in reality

The big idea here is that once The Universe Has Its Laws (and because and only because laws are stable or "eternal" indeed) there are such things called "principles" which describe some aspects of What Is.

For example, there is notion that a linear structure, such as protein, has an actual, explicit, "physical" ordering of its elements, BUT this ordering could be viewed from different points of view (different perspectives). This is the basic notion of relativity - observations depends on where do you place an observer, where do you place a zero, a center of your coordinate axis.

There is more. The same sequence view from different points of view could be read in exactly two ways, each way is what we call "reverse" of each other (but not the opposite - reverse is concrete ordering, opposition is an abstract nonsense).

Each sequence has exactly two readings of its actual physical orderings. So, we could abstract out this notion (as we did in our human language) and call it `reverse`. To "reverse" a sequence is to read it from the other end. Every sequence could be reversed, even empty sequence or a single element.

Knowing that we could define what it takes to reverse a sequences, which is a universal function

```reverse  =  foldl' (flip (:)) []
```

This declares that to reverse a `List` (a particular kind of a sequence) we should traverse all its elements and "cons them in the reverse order".

## Encapsulation of principles as concepts

Once we have the "higher" notion of reversion of a sequence we could encapsulate it for every kind of a sequence and abstract it out. (Actually, it is better to abstract out what it takes to be a sequence, and then encapsulate what it to reverse such a sequence).

Having that, we could define even higher level notion of a palindrome using the `reverse`

```palindrome xs = (xs == reverse xs)
```

which reads is this sequence reads the same from its both ends? or is this sequence a palindrome, which means that it reads the same in both ways.

This is what we mean by declarative programming - we compose notions, describing what it is (what it takes) instead of how to do it. Hows are encapsulated inside these higher-level abstractions the way particular aspects of a cell are encapsulated behind membranes of its organelles, and membranes of cells themselves.

Note that any cells themselves are possible because and only because this Universe has its laws.