Чистое функциональное программирование на D

#functional-programming #d #side-effects

#функциональное программирование #d #побочные эффекты

Вопрос:

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

Несколько вещей, которые я заметил:

std.algorithm в основном не помечено как pure , но потенциально может быть в значительной степени чистым, либо из-за чистой версии алгоритмов, требующих чистоты функции создания экземпляра или mixin, либо из-за того, что сам спецификатор чистоты является статически полиморфным.
Полезные преобразователи, подобные to!string( someInt ) , в настоящее время не являются чистыми.

Пользовательские структуры, похоже, имеют проблемы (как показано ниже) с:
1. чистыми деструкторами во вложенной структуре
2. чистой функцией postblit даже для не вложенной структуры

Следующий код в настоящее время выдает множество ошибок в 32-разрядной версии DMD 2.052 win

 struct InnerStruct
{
    pure this(this) {}
    pure ~this() {}
}

struct OuterStruct
{
    InnerStruct innerStruct;
    pure this(this) {}
    pure ~this() {}
}

pure void somePureFunc()
{
    OuterStruct s1 = OuterStruct(); // pure nested destructor does not compile
    OuterStruct s2 = s1;
    InnerStruct is1 = InnerStruct(); // pure non-nested destructor seems to compile
    InnerStruct is2 = is1; // pure non-nested postblit does not compile
}

void main()
{
    somePureFunc();
}
  
 pure_postblit.d(18): Error: pure function 'somePureFunc' cannot call impure function '__cpctor'  
pure_postblit.d(20): Error: pure function 'somePureFunc' cannot call impure function '__cpctor'  
pure_postblit.d(18): Error: pure function 'somePureFunc' cannot call impure function '~this'  
pure_postblit.d(17): Error: pure function 'somePureFunc' cannot call impure function '~this'  
  

Ответ №1:

Теоретически смысл pure в D заключается в том, что он должен обеспечивать гарантии отсутствия побочных эффектов у функции независимо от того, как эта функция реализована. В D существует два вида чистоты:

  • Все отмеченные функции pure слабо чисты. Они могут не иметь доступа к какому-либо глобальному изменяемому состоянию (глобальные переменные, локальные переменные потока, static переменные и т.д.) Или выполнять ввод-вывод. Однако они могут изменять свои аргументы. Суть этих функций в том, что они могут вызываться из строго чистых функций (подробно описано ниже) без нарушения гарантий строгой чистоты.

  • Все функции, которые являются слабо чистыми и не имеют никаких аргументов с изменяемой косвенностью, являются сильно чистыми. Для гарантии этого можно использовать конструкторы типа const и immutable . (При работе со структурами и классами this указатель считается параметром.) Строго чистые функции обладают всеми приятными свойствами, о которых говорят специалисты по функциональному программированию, даже если они реализованы с использованием изменяемого состояния. Строго чистая функция всегда возвращает одно и то же значение для любых заданных аргументов и не имеет заметных побочных эффектов. Строго чистые функции являются ссылочно прозрачными, что означает, что их возвращаемое значение может быть заменено вызовом к ним с заданным набором параметров, не влияя на наблюдаемое поведение. Любая строго чистая функция может быть безопасно выполнена параллельно с любой другой строго чистой функцией.

К сожалению, взаимодействие между универсальным кодом и pure (а также const и immutable ) довольно слабое. Было несколько предложений по исправлению этого, но ни одно пока не было принято.
std.algorithm написан так, чтобы быть как можно более универсальным, поэтому он не может требовать, чтобы его лямбда-функции и диапазоны, которые он принимает, были чистыми. Кроме того, функции системы типов, которые были добавлены в D2, как правило, являются наиболее проблемными функциями в языке, потому что более базовые вещи были приоритетными перед устранением соответствующих проблем. Прямо сейчас pure в принципе не используется, за исключением тривиальных случаев, таких как std.math.

Комментарии:

1. Спасибо за ваши комментарии. Некоторое время назад, экспериментируя, я заметил слабое определение чистоты, и оно явно очень мощное, позволяющее полностью изменять OO-программирование в чистом коде, а при создании блоков отложенной оценки или планировании обещаний и т.д. Строгая форма может быть легко подтверждена метапрограммированием в квалификаторах типов. Я думаю, что для того, чтобы видение с высокой степенью параллелизма действительно заработало, гораздо больше должно быть в состоянии находиться внутри чистой оболочки. Проблемы с деструктором и postblit, о которых я упоминал, больше всего влияют на меня, поскольку мне нужно подсчитывать ссылки в чистом коде, вы думаете, это ошибки?

2. @John: Да, это, вероятно, ошибки.