Функциональный GOTO

В любом крупном Java/C#/C++/…-проекте обычно можно найти множество функций, «возвращающих» void — то есть не возвращающих ничего, а просто выполняющих какие-то действия. Это типичная манера императивных кодировщиков, имеющая очевидный серьёзный минус.

 

Небольшое отступление: существует такой стиль программирования, continuation-passing style (CPS), когда, примитивно говоря, каждой команде в коде мы явно задаём следующую команду (функцию), которая получает на вход результат исходной функции. Такая форма вызова функций, когда появляется дополнительный параметр (продолжение), и есть CPS. Эта концепция появилась на свет в 1975-м, в языке Scheme.

 

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

 

Писать код в CPS-стиле не очень удобно, но в ряде языков существует, во-первых, синтаксический сахар, а во-вторых, некоторые компиляторы умеют выполнять такие преобразования сами. Важно, что мы в таком случае вообще избавляемся от стека вызовов, так как теперь всегда понятно, что же делать с результатом любого вычисления. Более того, чтобы прервать и возобновить работу программы, нам нужно всего лишь запомнить текущее продолжение, и даже возвращаться по вычислениям обратно по коду! Да и ленивые компиляторы начинают работать существенно эффективнее, решая все проблемы с остаточными вычислениями.

 

Например, в технологию ASP.NET вложены огромные ресурсы именно для организации сохранения состояния в промежутках между клиентскими запросами. А если бы в C# существовала поддержка CPS, то сложность ASP.NET можно было бы снизить в разы.

 

Можно сказать, что CSP-преобразование — это такой функциональный оператор GoTo, потому что он может прерывать классический поток вычислений произвольным образом, в духе короутин и эксепшенов, и подчас бывает сильно непривычен.

 

Вернёмся к проблеме с void, которая в языках типа C# отнюдь не в типе void, а прежде всего в том, что любая функция в программе потенциально нечиста. Может быть, она выполняет считывание данных из файла или из базы, обращается к глобальным переменным, отправляет данные по сети, и т. п. Общая идея довольно парадоксальна: с одной стороны, нам нужно строить цепочки вычислений, передающих друг другу результаты, но с другой стороны, мы реализуем их через преобразование вообще всех наших функций в тип, возвращающий void! Но в итоге получается красивейший синтаксис.

 

Далее мы рассмотрим конкретные примеры организации CPS-трансформации.

Поделиться статьей ...Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Share on VKPrint this page

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *