Для многих самой чистой формой абстракции кода в современную эпоху бинарного программирования является «функция высшего порядка». По сути, сама функция обрабатывается как данные, а функции функций определяются так же, как вы могли бы видеть их в математических уравнениях с операторами, определяющими результат их операндов, и предопределенным порядком операций, определяющих «вложение» этих операций. Математика имеет очень мало «императивных команд» в своей структуре; два примера, которые я могу придумать: «пусть x будет иметь какое-либо значение или будет любым значением, соответствующим некоторому ограничению», и «кусочные функции», в которых входные данные определяют выражение, необходимое для создания выходных данных. Эти конструкции легко представимы как их собственные функции; «функция» х всегда возвращает 1, а «перегрузки» функции определяются в терминах того, что им передается (что в отличие от объектно-ориентированных перегрузок может быть определено на основе ввода значений), что позволяет «кусочно» оценивать именованную группу функций, даже в терминах самих себя. Таким образом, программа покончила с понятием императивов на низком уровне и вместо этого сосредоточилась на «оценке себя» с учетом вводимых данных.
Эти функции высшего порядка составляют основу «функциональных языков»; то, что делает программа, определяется в терминах «чистых функций» (один или несколько входов, один или несколько выходов, отсутствие побочных эффектов или «скрытое состояние»), которые вкладываются друг в друга и оцениваются по мере необходимости. В таких случаях большая часть «императивной логики» отвлекается; среда выполнения обрабатывает фактический вызов функций и любые условия, при которых может потребоваться вызов той или иной перегрузки функции. В такой программе код не считается «делающим» что-то, он считается «существующим» чем-то, и что именно это определяется, когда программа выполняется с начальным вводом.
Функции высшего порядка теперь также являются основой многих императивных языков; Лямбда-операторы .NET в основном допускают «анонимный» функциональный ввод в другую «функцию» (реализована обязательно, но теоретически не обязательно), что позволяет легко настраивать «цепочку» «универсальных» функций для достижения желаемый результат.
Другая абстракция, обычно встречающаяся в последнем раунде языков программирования, - это типизация динамических переменных, основанная на концепции «типизирования по типу утки»; если это похоже на утку, плавает как утка, летит как утка и крякает как утка, вы можете назвать это уткой. Неважно, если это на самом деле кряква или холст. Это может иметь значение, если это на самом деле гусь или лебедь, но с другой стороны, это может не иметь значения, если все, что вас волнует, это то, что он плавает и летает, и вроде как утка. Это считается окончательным в наследовании объекта; Вам не все равно , что это будет , за исключением того, чтобы дать ему имя; что важнее то, что он делает, В таких языках есть в основном только два типа; «атом», отдельный элемент информации (одно «значение»; число, символ, функция и т. д.) и «кортеж», состоящий из атома и «указателя» на все остальное в кортеже. То, как эти типы реализованы в двоичном виде во время выполнения, не имеет значения; используя их, вы можете достичь функциональности практически всех типов, которые вы можете себе представить, от простых типов значений до строк и коллекций (которые, поскольку значения могут быть разных «типов», допускают «сложные типы», то есть «объекты»).