Добрый день, Василий! Такая технология мне понятна, но речь идет о простоте в использовании для "рядового" программирования. Кроме того в больших проектах не навставляешься таких строк. Их как раз может добавлять суперкомпилятор при подготовке программы к исполнению.
>Среда, 18 декабря 2019, 10:36 +03:00 от Stelletsky V <s...@cnshb.ru>: > >Добрый день! >Александр! Есть 3-й самый простой вариант: добавляете в проблемную функцию еще >одно (или больше) предложение – вот Вам и обработка неуспеха! Если они что-то >выводят – можете проанализировать «листинг»… >Я, например, после «сложных» программ, которые могут «свалиться» делаю проверку >на наличие «дампа» и в этом случае останавливаю выполнение bat -файла, >а то и шлю себе на почту сообщение об аварии… > >С уважением, >Василий Стеллецкий >-- >Vasily Stelletsky mailto:s...@cnshb.ru mailto:sw...@ya.ru >http://www.cnshb.ru/vniitei/sw/ http://sw710.narod.ru >---------------------------------------------------------------------- >From: Александр Гусев >gusev_aleksandr_AT_mail.ru [mailto:refal@botik.ru] >Sent: Wednesday, December 18, 2019 >9:44 AM >To: refal@botik.ru >Subject: Re: Прогонка по Турчину и >неуспехи > >Доброго утра! > >Вопрос с неуспехами очень важен по-моему, просто краеугольный вопрос. Все >современные языки включают в себя такие средства, поскольку они существенно >повышают производительность труда программистов. > >Предлагаю взглянуть на всё с практической точки зрения. Что нужно, чтобы >обучить с нуля и посадить программировать но Рефале 20-30-100 человек для >решения практических задач. Проблема обработки неуспехов тут на очень важном >месте, поскольку самая продвинутая программа может "упасть" из-за >оплошности в одной вроде бы незначащей функции. И сложность поиска решения мало >зависит от сложности и важности этой функции. > >Напрашиваются два решения: >1. либо расширять язык обработкой неуспехов, что приведёт, скорее всего, к >возрастанию сложности понимания языка; >2. либо пытаться решить проблему средствами суперкомпиляции, либо исправляя >"сомнительные" места, либо на них указывая. Это сильно сложнее, но >зато скрыто от пользователя - вполне заурядного программиста и ему сильно >легче. > >Сейчас ни тот ни другой путь ещё не пройден до конца, как я думаю. > >Интересно, есть ли ещё варианты? > >Да, мне кажется, что базисный Рефал - это минимум, ниже которого опускаться не >следует. Это сильно сужает гибкость языка и может служить только чисто >теоретическим целям. >Среда, 18 декабря 2019, >1:16 +03:00 от Александр Коновалов a.v.konovalov87_AT_mail.ru >< refal@botik.ru >: >Доброй ночи всем! >Пришло >в голову одно интересное соображение. Но сначала контекст. >В 1974 году >Турчин описал прогонку как эквивалентное преобразование программы >на Рефале ( Москва: ЦНИПИАСС, 1974 ( pdf ) ). >На самом деле прогонка была описана на два года раньше ( Киев-Алушта, 1972 ( >pdf ) ), >но там термина «прогонка» ещё не было. >В этих >работах описывается подмножество базисного Рефала — ограниченный Рефал , в >котором >в образцах запрещены любые t -переменные >и открытые и повторные e -переменные. >Для этого подмножества определена прогонка — >замена одного из предложений функции F , >содержащей вызов функции G на эквивалентный >набор предложений (в том числе и пустой), в которых вызов G отсутствует. При >этом семантика функции F на исходной области определения не меняется. >Однако, область определения функции F при этом >может расшириться — если ранее программа вылетала с ошибкой >невозможности отождествления, то после прогонки одного из вызовов >функции программа может перестать падать (вместо чего выдавать какой-то >результат или зацикливаться). >Алгоритм прогонки >я здесь описывать не буду, поскольку он есть в статьях >по гиперссылкам выше. Лучше читать работу Киев-Алушта, 1972 ( pdf ) , >поскольку >она короче. Прогонка в ней — правило EF 1. >Покажу >на примере, как прогонка расширяет область определения. Пример простой, >но расписан подробно, читать рекомендуется по диагонали. >Буду использовать >синтаксис Рефала-5, поскольку мне он более привычен. >F { > A e . Z = 1 e . Z ; > s . X e . Z = < G s . X > e . Z ; > t . X e . Z = 100 e . Z ; >} > >G { > P = >10; > Q = >20; >} >При прогонке мы >комбинируем левые части предложений прогоняемой функции G с левой частью >предложения, содержащего вызов >прогоняемой функции. Сам вызов прогоняемой функции заменяем >на соответствующие правые части. В результате получится такая функция F : >F { > A e . Z = 1 e . Z ; > P e . Z = 10 e . Z ; > Q e . Z = 20 e . Z ; > t . X e . Z = 100 e . Z ; >} >Но, можно >заметить, что область определения расширилась. Если ранее вызов < F >X Y Z > падал: >< F X Y Z > → < G X > Y Z → ошибка >то теперь он >выдаёт ответ: >< F X Y Z > → 100 Y Z >Почему так >происходит? >Рассмотрим >сначала корректный случай, например, < F Q R >S >. >До прогонки : ><F >Q R S> → <G Q> R S → 20 R S >В исходной >функции F аргумент >сопоставится с левой частью второго предложения. Вызов заменится >на правую часть, где уже будет располагаться вызов < G >Q >. Для этого вызова применится второе предложение G , >поскольку первое будет неприменимо. Т.е. сначала второе предложение F , >а затем второе предложение G . >После прогонки: >< F Q R S > → 20 R S >После прогонки >сразу активируется третье предложение новой функции F , которое >является комбинацией исходного второго предложения F и исходного >второго предложения G . Второе >предложение новой функции F здесь тоже >будет неприменимо, поскольку оно является комбинацией исходного второго >предложения и первого предложения функции G . >Теперь вернёмся >к примеру < F X Y Z >. >До прогонки активировалось второе предложение F , после >чего вызов G падал, поскольку >ни одно из его предложений не применимо. После прогонки >становятся неприменимыми второе и третье предложения новой функции F (т.к. >неприменимы их прообразы в G ) >и управление передаётся на четвёртое предложение. >Т.е. область >определения может расширяться на те случаи, где прогоняемый вызов >должен был падать. (А может и не расширяться, если, >к примеру, прогоняемый вызов никогда не падает или предложение с этим >вызовом самое последнее.) > >Теперь >перехожу к сути письма. >Условимся, что >прогонять мы будем только самый первый вызов с пассивным аргументом — >в этом случае мы избежим нарушения порядка вычислений функций для >неленивого Рефала. При этом вот ограничении прогонка >будет сохранять область определения, если дополнить ограниченный Рефал >неуспехами. >Определим такой ограниченный Рефал-6 — подмножество >Рефала-6, в котором предложения могут иметь вид « L -образец, >результат». Т.е. в отличие от базисного Рефала, в ограниченном >Рефале-6 правая часть отделена от левой не равенством, >а запятой . >Что это даёт. >Если в Рефале-6 ни одно из предложений функции оказалось >неприменимо, то программа аварийно не завершается, вместо этого >функция вырабатывает особое значение — «неуспех». Если функция возвратила >неуспех в результатном выражении после знака «=», то программа уже >падает с ошибкой «неперехваченный неуспех». Если неуспех возник >в результатном выражении после знака «,», то он может быть перехвачен >и обработан программой. Я здесь не буду подробно описывать семантику >неуспехов, она есть в руководстве к Рефалу-6 . Отмечу лишь, что >в программах ограниченного Рефала-6 управление в случае неуспеха >будет передаваться на следующее предложение. >Рассмотрим такую >программу на ограниченном Рефале-6: >F { > A e.Z , 1 e.Z; > s.X e.Z , <G s.X> e.Z; > t.X e.Z , 100 e.Z; >}; > >G { > P , 10; > Q , 20; >}; >Рассмотрим вызов >< F X Y Z >. Первое предложение F окажется неприменимо. Применится второе >предложение. >В правой части будет выполняться вызов < G X >. Оба >предложения функции G окажутся >неприменимы — этот вызов вернёт неуспех. Поскольку правая часть второго >предложения вернула неуспех, управление будет передано на третье >предложение. Третье предложение успешно вычислится в 100 Y >Z . >Для вызова < F > >ни одно из предложений F окажется >неприменимо, поэтому такой вызов выработает неуспех. >Если мы для >ограниченного Рефала-6 будем применять прогонку, как она описана у Турчина, >то область определения меняться не будет. Для этого примера мы >получим: >F { > A e.Z , 1 e.Z; > P e.Z , 10 e.Z; > Q e.Z , 20 e.Z; > t.X e.Z , 100 e.Z; >} >Нетрудно >заметить, что область определения не изменилась. Почему? Если >до прогонки активировалось второе предложение F , >но ни один из образцов G не был >применим, то вырабатывался неуспех и управление передавалось >на третье предложение старой F . После >прогонки оказываются неприменимы оба новых предложения и управление >естественным путём передаётся на четвёртое предложение новой F . > >Неуспехи были >введены в Рефале-4 ( Романенко, 1987 ( pdf ) ), правда там >они назывались неудачами. Особенностью Рефала-4 было то, что он замкнут >относительно операции прогонки, при этом допускает образцы общего вида >(в отличие от L -образцов >в ограниченном Рефале). Позже из Рефала-4 неуспехи перекочевали в Рефал Плюс, >а оттуда уже в Рефал-6. Поэтому то, о чём я пишу, >не новость — это должно было быть очевидно Сергею Романенко, когда он >проектировал Рефал-4 и Рефал Плюс. Когда-то давно разрабатывался >суперкомпилятор-оптимизатор для Рефала-6. Если в Рефале-6 на тот момент >уже были неуспехи, то эта особенность прогонки тоже могла быть известна >авторам суперкомпилятора. >Так что я >не претендую на эпохальное открытие, а делюсь, как мне кажется, >интересным наблюдением. > >Суперкомпилятор >для ограниченного Рефала будет расширять область определения программы >по двум причинам. Во-первых, Рефал язык аппликативный, >а суперкомпилятор реализует ленивую семантику. А вторая причина была >подробно разобрана в этом письме. И если первая — плата >за бо́льшую глубину преобразований, то вторую можно преодолеть >несколькими способами. >Можно >в исходных программах использовать только ортогональные образцы + >условия-неравенства. Любую программу на ограниченном Рефале >(не ограниченном Рефале-6) можно преобразовать в эквивалентную >с непересекающимися образцами с условиями-неравенствами. >Можно >к каждой функции неявно добавлять предложение вида >F >{ > ... > e.X = <F$fail e.X>; >} >где F $ fail — >(примитивная) функция, которая падает на любом аргументе. Такие вызовы >будут падать в остаточную программу ради сохранения области определения. >Так сделано в оптимизаторе-прогонщике Рефала-5λ (он >не суперкомпилятор, но прогонка в нём есть). >И, наконец, можно >вместо ограниченного Рефала использовать ограниченный Рефал-6. А если >определить ограниченный ленивый Рефал-6, то область определения программы >будет сохраняться всегда. > >С уважением, >Александр Коновалов > > >С уважением, >Александр Гусев >gusev_aleksa...@mail.ru С уважением, Александр Гусев gusev_aleksa...@mail.ru