Причины программирование

Стандартная библиотека типичного языка программирования часто заполнена методами, которые явно дополняют друг друга. Ясное и общее отношение существует между методом операции и методом предиката, который становится истинным. Если эта операция имела место. Например, сразу после вызова clearметода в экземпляре Ruby Arrayempty?предикат становится истинным. Существует множество других способов мутировать массив таким образом. Чтобы он удовлетворял empty?предикату, но clearгарантированно удовлетворял его каждый раз только одним вызовом метода. Подводя итог: призвание clearзаставляет empty?быть истинным.

Теперь мы установили, что между этими методами существует связь.

Что, если бы мы могли объявить такие отношения к языку, и какие преимущества это принесло бы как программисту. Так и самому языку?

Давайте рассмотрим теоретический язык, который позволяет объявлять подобные отношения. Мы будем называть эти отношения причинами, так как вызов одного метода приводит к тому. Что другой предикат становится истинным.

Я буду писать псевдокод в стиле Ruby. Поскольку реализация такой сложной функциональности с использованием метапрограммирования Ruby кажется вполне осуществимой.

Вот как методы empty?and clearмогут быть объявлены в Arrayклассе с заданной причиной для

clear:

class Array # ...other definitions... def empty? length.zero? end causes { empty? } # def clear each do |item| delete(item) end end end 

Этот код будет связывать методы empty?andclear, указывая, что вызов clearприводит к тому. Что предикат empty?становится истинным.

Это также может быть распространено на более сложные причины, основанные на аргументах, переданных методу. Например, если элемент только что был добавлен в массив (используется

в Ruby), то он должен быть последним элементом в этом массиве.

Определение этой причины может выглядеть следующим образом:

cause { |item| last == item } def (item) # ...array append logic... end 

Здесь предикат представляет собой нечто большее. Чем простой вызов метода — lastметод вызывается и его результат сравнивается с добавляемым элементом.

Размышление о причинах метода кажется еще одним препятствием при написании кода, так зачем же беспокоиться?

Идемпотентность без усилий

Поскольку точно указано, что произойдет, когда они будут вызваны. Простые методы с причинами могут быть вызваны идемпотентно.

То есть, если их эффект уже произошел, он не должен повториться.

Предположим, у вас есть массив байтов, вызванных bytesпользователем, и вы собираетесь обработать его таким образом. Чтобы в конце был нулевой терминатор. Пользователь может включать или не включать этот нулевой терминатор. В традиционном коде Ruby это можно сделать так:

bytes  0 unless bytes.last == 0 

Введя в наш язык синтаксис идемпотентного вызова, где мы добавляем ?префикс к имени метода. Мы могли бы сделать следующее:

bytes ? 0 

Это возможно потому, что, указав, что метод вызывает формально, мы точно знаем, что будет делать. И поэтому можем определить. Требуется ли его вызывать. Этот конкретный фрагмент кода будет оценивать предикат, указанный в причине for ; напомним. Что этот предикат является |item| last == item. Если этот предикат ложен, то есть последний элемент не равен 0, то будет выполнен.

Приведение декларативного программирования к процедурному языку

Если известно, какому условию удовлетворяет метод, то есть также возможность перевернуть эту информацию. При наличии условия. Которое мы хотим удовлетворить. Мы можем найти метод. Который его вызывает.

Предположим. Что у нас есть множество алгоритмов сортировки. Определенных на типе массива языка. Каждый из которых имеет определенную причину. Так что массив удовлетворяет sorted?предикату после их вызова. Чтобы отсортировать экземпляр массива, мы можем написать код, который просит язык удовлетворить sorted?предикат. Используя satisfyключевое слово:

array = [4, 3, 7, 2] satisfy array.sorted? p array # => [2, 3, 4, 7] 

Язык знает, какие методы будут удовлетворять sorted?предикату, и может выбрать один из них соответственно, возможно. Используя интеллектуальный интерпретатор. Который пробует каждый метод-кандидат с течением времени и устанавливает. Какой метод быстрее для конкретных экземпляров.

Дополнительные утверждения бесплатно

Каждая причина может опционально действовать как утверждение постусловия. Где она выполняется после вызова связанного метода. Это похоже на контрактные функции, встроенные в Eiffel или D. Например, в clearempty?примере and язык будет проверять. Что список действительно пуст. Когда clearвозвращается. И выдавать ошибку утверждения, если нет. Это может помочь поймать ошибки раньше.

Более легкий для чтения код

Каждая причина может действовать как документация. Показывая программисту. Читающему код. Какие последствия будет иметь метод. Кроме того, поскольку причины могут выступать в качестве утверждений, гарантируется, что эти следствия истинны.

Я думаю, что реализация причин в языке может быть чистым. Неинтрузивным способом сделать код более выразительным и простым для чтения. А ты как думаешь?