97 KiB
История применения и оценки функционального программирования.
- История применения и оценки функционального программирования.
- Часть 2: Великое уравнивание
- Литература
Часть 2: Великое уравнивание
Существует ряд довольно похожих языков, из которых, пожалуй, наиболее известен HOPE. И то, что представлено здесь, можно считать иллюстрацией современного стиля функционального программирования и противопоставить его более традиционному стилю функционального программирования, основанному на LISP.
Дэвид Тернер, Функциональные программы как исполняемые спецификации [Turn84].
В нулевой части истории мы выяснили, что к началу 80-х годов первый функциональный язык современного вида, с выводом полиморфных типов, АлгТД и паттерн-матчингом уже существовал [Burs80]. Но вышло так, что ни один из первого поколения компиляторов ФЯ, обзор которых мы сделали в первой части, не начал с имплементации такого языка.
В результате в начале 80-х появилось заметное число самобытных функциональных языков. Но им не долго оставалось быть существенно отличающимися друг от друга, да и вообще быть.
Вскоре начался процесс их унификации. Он включал в себя и скоординированные усилия по созданию одного универсального языка, и стремления отдельных разработчиков добавить в свой язык фичи как у всех. В результате немногие оставшиеся функциональные языки Эдинбургской исследовательской программы приобрели свой современный, узнаваемый вид. Об этом процессе мы и расскажем во второй части нашей истории.
Синтаксическая элегантность уравнений
Не смотря на все описанные в прошлой части успехи по компиляции ФЯ, HOPE - первый ФЯ современного вида - все еще оставался имплементированным с помощью медленного интерпретатора. Чего недоставало компилируемым функциональным языкам для того, чтоб догнать передний край худо-бедно интерпретируемых?
Все они уже функциональные, идеи Берджа восторжествовали после пары не самых простых для них десятилетий. Даже некоторые лисперы уже узнали про возвращение функций из функций и о том, что это неплохо бы поддержать в имплементации языка. Конечно, то, что несколько имплементаторов ФЯ теперь понимают возвращение функций из функций - это еще не значит, что это что-то широко известное. И донесение этого до более широкой общественности - основная тема и предназначение статей и докладов из которых можно было впервые узнать об остальных фичах.
Вывод типов Хиндли-Милнера достаточно хорошо известен и обычно либо уже имплементирован (в VAX-ML, LML и Cambridge ML) или не имплементирован потому, что автору языка хотелось бы чего-то большего и это что-то большее уже имплементировано вместо него (Ponder, Poly).
Хуже всего дела с АлгТД и уравнениями с паттерн-матчингом. Глава Хоара про композитные типы данных [Hoar72], написанная до изобретения BNF-образной формы АлгТД намного известнее, чем статья в которой такая форма описана [Hoar75]. Паттерн матчинг в VAX-ML самобытный, работающий не с привычными АлгТД. В ALFL есть уравнения с ПМ как в SASL, работающие только со встроенными списками.
Работавшие над языками с уравнениями с ПМ Бурсталл, Дарлингтон и Тернер не достаточно писали о своей работе над уравнениями с ПМ. В 70-е все эти уравнения оставались в обычно диссертациях, университетских отчетах и руководствах пользователя. Тот кто читал про работу Дарлингтона с Бурсталлом, как правило читал о ней в статье [Darl76] в которой уравнений еще нет. И если это легко объяснить тем, что когда статья была написана - уравнений с ПМ еще не было и статья просто долго ждала публикации, то похожую проблему со статьей Тернера [Turn79] объяснить сложнее. В самой популярной и цитируемой статье Тернера об SKI-интерпретаторе, вдохновившей так много героев нашей истории, Тернер по какой-то причине не посчитал нужным продемонстрировать уравнения с ПМ в новом SASL 76. Код похож на написанный на старом SASL и, следовательно, на ISWIM.
Карделли, скорее всего узнавший об уравнениях с ПМ таким же образом как и Тернер, приехав в Эдинбург, выбрал имплементировать ПМ и композитные типы данных не так как в HOPE. И Дарлингтон с Тернером выбрали (пока что) не имплементировать компиляторы своих языков с уравнениями для обычных машин.
В результате, книга [Hend80] об ФП одного из изобретателей ленивости Хендерсона, вышедшая спустя пять лет после книги Берджа все так же использует ISWIM, а не язык уравнений с паттерн-матчингом. Хендерсон описывает разбор структур в неформальной нотации, напоминающей Ландинскую, после чего имплементирует со всеми предикатами if-ми и селекторами. Одноуровневый ПМ и case-выражение упоминаются только как интересная концепция с одним примером. При том, что Хендерсон ссылается на работы Бурсталла и Тернера. Но, конечно же те, в которых они не посчитали нужным продемонстрировать уравнения с ПМ.
Бегство из MACSYMA
По большему счету все эти уравнения с ПМ в функциональных языках были представлены миру только на первых ФП конференциях в 80-е, когда работа над первыми компиляторами ФЯ уже шла вовсю.
В том, что первые ФП-конференции состоялись только в 80-е нет ничего удивительного. Как мы уже выяснили в нулевой части, до начала 80-х функционального программирования не было. Но чего наши читатели, скорее всего, не ожидают, так это того, что первая ФП-конференция была и первой регулярной Лисп-конференцией [Stee82b]. До нее была только конференция 64-го года в Мехико.
Где же лисперы докладывали о своей бурной деятельности, например о разработке MacLisp [Whit77] или NIL [Whit79]? Разумеется, на конференциях пользователей MACSYMA. Ведь, как мы уже выяснили в нулевой части, Лисп - это в первую очередь язык для имплементации MACSYMA, а все остальное - как повезет.
Но в 80-е Лисп довольно успешно освобождается от главного бремени (и смысла) своего существования, так что есть все основания начать проводить конференцию посвященную именно Лиспу.
Конференцию организовали и профинансировали Джон Аллен (John Allen) со своей женой Рут Дэвис (Ruth E. Davis) [McJo22]. Аллен работал в Стенфорде над тем самым мини-Маклиспом для не таких богатых лисперов из Стенфордского мини-Мака, который позднее использовал уже в Эдинбургском мини-Маке Милнер для написания LCF/ML. В конце 70-х Аллен основал The Lisp Company, которая разрабатывала Лисп для x86-машин.
Джон Аллен - не обычный лиспер, но лиспер, написавший книгу о Лиспе [Alle78], в которой ссылается не только на большинство имеющих какое-то отношение к ФП лисперов, но и на большинство героев обоекембриджской и ранней эдинбургской частей нашей истории, а также оказавших на них влияние. На Бойера, Берджа, Бурсталла, Черча, Карри, Дарлингтона, Гордона, Ландина, Милнера, Джея Мура, Джеймса Морриса, Локвуда Морриса, Ньюи, Плоткина, Поплстоуна, Рейнольдса, Скотта, Стрейчи (в том числе на тот самый доклад [Stra67]), Вадсворта (в том числе и на его диссертацию про редукцию графов), Вюийемена и, чтоб охватить совсем уж все имеющее отношение к ФП, Вейнгаардена, Algol 68 и прочих алголистов.
Что только частично можно объяснить стенфордскими связями авторов LCF и вообще отличием стенфордских лисперов от гораздо более стойко сопротивляющихся всему эдинбургскому лисперов МТИ.
Так что нет ничего удивительного в том, что он не хотел ограничиваться только Лиспом [Alle2005] и организовал первую конференцию по Лиспу, ставшую первой в серии проходящих раз в два года конференций по Лиспу и функциональному программированию (Lisp and Functional Programming Conference).
Конференция прошла в конце августа 1980-го года в Стенфорде, вскоре после первой конференции AAAI. Да первые ИИ-конференции, AAAI и ICML тоже начали организовывать только в 1980-ом году. Для тех, кто работает над каким-нибудь ИИ, который не является системой компьютерной алгебры MACSYMA.
Именно на этой конференции можно было услышать доклад о HOPE [Burs80] (и SKIM, что не так важно для этой части нашей истории).
Доклад о HOPE содержит редкий пример объявления АлгТД современного вида
data otree == empty ++ tip(num)
++ node(otree#num#otree)
и разбирающих его функций, написанных как уравнения с ПМ
dec insert : num#otree -> otree
--- insert(n,empty) <= tip(n)
--- insert(n,tip(m))
<= n<m then node(tip(n),m,empty)
else node(empty,m,tip(n))
--- insert(n,node(t1,m,t2))
<= n<m then node(insert(n,t1),m,t2)
else node(t1,m,insert(n,t2))
Примеров работы со встроенными типами вроде списков и натуральных чисел в то время было куда больше, тем более, что SASL и KRC поддерживали только их и большая часть ранних демонстраций уравнений с ПМ - это SASL и KRC.
Существует отчет [Stee82b] Стила о конференции с комментариями о каждом докладе. Так что у нас есть возможность узнать, что лисперы думали о ФЯ современного вида, когда они только появились.
Авторы утверждают, пишет Стил, что не пытаются быть оригинальными, а просто выбирают уже проверенные, хорошо изученные идеи. Но само сочетания идей - оригинально, решает Стил.
Итак, Стил признает HOPE и, соответственно, ФЯ современного вида чем-то новым. Но и для нового можно найти место в уже существующей классификации среди знакомых вещей.
Так, в нулевой части мы выяснили, что авторы языков алгебраической спецификации считали HOPE языком алгебраической спецификации. Пишущий главу о логических языках О'Доннел решал, что HOPE - логический язык. И Бурсталл не то чтобы был с ним не согласен. Тернер считал, что если и не логический, то ближайший родственник логических языков [Turn84].
Так что ничего удивительного в том, что лиспер решил, что HOPE - это типизированный, аппликативный Лисп. Лисперы даже включили интерпретатор HOPE, написанный в Эдинбурге на POP-2 в список имплементаций Лиспа, который составляли на конференции [Stee82b].
В Ньюкасл со своими уравнениями
В июле 81-го в Университете Ньюкасла состоялось мероприятие, сравнимое с тем, чем была летняя школа 63-го года по "нечисленным вычислениям" для героев нулевой части нашей истории.
Десять лекторов, в том числе и такие важные герои истории ФП как Сассман, Уайз, Хендерсон и Джеймс Моррис прочли десять коротких курсов из трех-четырех лекций восьмидесяти слушателям, среди которых были Джон Хьюз и Саймон Пейтон-Джонс [Huda07]. Но важнейшими для продвижения языков с уравнениями и паттерн-матчингом были доклады Тернера и Дарлингтона.
Еще три доклада должны были прочесть приглашенные знаменитости, но Дана Скотт и ФП-алголист Фриц Бауэр не приехали, прислав замены. Не для всех эти обстоятельства оказались неудачными, заменявший Бауэра докладчик не дал упасть с лестницы третьей и единственной приехавшей приглашенной знаменитости - Эдсгеру Дейкстре.
Дейкстра прослушал половину лекций и написал отчет [Dijk81] о них. Достаточно критический даже по меркам Дейкстры отчет, в котором для лисперов не нашлось добрых слов. Но отзыв Дейкстры о докладах Дарлингтона и Тернера более-менее положительный, хотя и не без критики и иронии над грандиозной недописанной еще системы трансформации программ Дарлингтона. Дейкстра утверждает, что в докладе Тернера было больше нового, чем во всех прочих, но и преувеличивает важность своей темы Тернер больше, чем все остальные докладчики.
Дейкстра не упоминает в своем отчете то, что он уже знаком с Тернером и его работами. Но Тернер вспоминает [Hoar22], что они с Дейкстрой познакомились за год до того, что Тернер обсуждал с Дейкстрой SASL. Так что новое в данном случае, скорее всего, не для Дейкстры.
Сборник Ньюкаслских лекций вышел в 82-ом году под названием "Функциональное программирование и его применения" [Darl82].
Функциональное программирование привлекло к себе внимание, констатируют составители сборника Дарлингтон, Хендерсон и Тернер. Почему? Из-за лекции Бэкуса, продолжающегося "кризиса программного обеспечения" и "революции аппаратного обеспечения". "Кризисом программного обеспечения" называют то, что развитие обычных языков программирования и методологии программирования не дает ожидаемого роста надежности и падения стоимости разработки программного обеспечения. Ничего удивительного, отмечает Тернер. Обычные языки слишком похожи друг на друга, изменения были не достаточно радикальными, чтоб от них был заметный эффект. Разумеется, у Тернера есть идеи достаточно радикальных изменений.
"Революцией аппаратного обеспечения" Дарлингтон, Хендерсон и Тернер называют то, что равномощный мэйнфрейму 70-х компьютер становится все меньше и дешевле. Как мы уже выяснили, удешевление памяти сыграло решающую роль в том, что функциональное программирования стало возможным на практике. Но составители сборника имеют в виду не это, а неминуемое появление параллельных компьютеров, для программирования которых лучше использовать ФЯ. Как мы уже выяснили в предыдущей части, в последующие пять лет это не нашло особого подтверждения.
Сборник лекций и открывающая его лекция Тернера [Turn82] "Рекурсивные уравнения как язык программирования" полны рассуждений о том, как нужно ФП для параллельных компьютеров и как параллельные компьютеры нужны для ФП. Мы уже кратко останавливались на этих идеях.
Но, к счастью, функциональное программирование нужно не только для программирования параллельных компьютеров. Свойства функционального кода легче доказывать. Функциональный код легче трансформировать в более эффективный. Но главное, функциональное программирование нужно для того, чтоб писать меньше кода.
Исследования показали, объясняет Тернер, не давая ссылок на эти исследования, что программист производит за год фиксированное количество отлаженного и документированного кода. Примерно полторы тысячи строк. Независимо от того, на чем он эти строки пишет, на ассемблере, на Фортране или на ФЯ. Но, разумеется, полторы тысячи строк на Фортране это не то же самое, что те же полторы тысячи на ассемблере. Код на Фортране в пять - десять раз короче кода на ассемблере, который делает то же, объясняет Тернер, не давая ссылок и в этом случае и не объясняя какого именно ассемблера. Поэтому Фортран такой грандиозный шаг вперед в развитии программирования. Он делает программиста в 5-10 раз продуктивнее.
Но со времен появления Фортрана прошло уже 25 лет, а новый язык, который был бы для Фортрана тем же, чем Фортран был для ассемблера, все не появлялся. Кризис программного обеспечения!
Но не нужно впадать в отчаянье. Такие языки долго не появлялись, но, наконец, появились. Это аппликативные, они же функциональные языки. Но, конечно же, не Лисп, который "все еще приходит на ум, когда говорят о функциональных языках", поясняет Тернер. Функциональные языки, которые он имеет в виду - это SASL и KRC.
Смотрите сами. Вот Лисп, показывает Тернер:
DEFINE(((A (LAMBDA (M N)
(COND ((ZEROP M) (PLUS N 1))
((ZEROP N) (A (SUB1 M) 1))
(T (A (SUB1 M) (A M (SUB1 N)))
))))))
А вот KRC:
A 0 n = n + 1
A m 0 = A (m-1) 1
A m n = A (m-1) (A m (n-1))
В своей лекции из того же сборника [Darl82] Дарлингтон сравнивает уравнения с паттерн-матчингом и многоветочные if наподобие лисповых в одном и том же языке:
fact(0)=1
fact(n+1)=(n+1)*fact(n)
fact(n)=1 if n=0
n*fact(n-1) otherwise
И этот язык скорее NPL, чем HOPE. Дарлингтон упоминает HOPE, но в примерах не использует синтаксические детали, которые появились в NPL/HOPE с тех пор как Дарлингтон ушел из Эдинбургского Университета.
Эти примеры в какой-то степени демонстрируют преимущества уравнений с паттерн-матчингом. Но не так хорошо, как сравнение из доклада Уоррена о ненужности Лиспа [Warr77] [Warr77b]. Паттерн матчинг в примере Уоррена несколько интереснее потому, что разбирает списки. И Уоррен сравнивает паттерн матчинг Пролога с селекторным подходом Лиспа, используя его несуществующий M-синтаксис из статей, вместо существующего скобочного. Но Тернер и не скрывает, что хочет показать Лисп в плохом свете, а не только селекторный подход. Дарлингтон же не особенно заинтересован в сравнении с чем бы то ни было, он приводит конкатенацию списков в виде уравнений с ПМ в примере на следующей после факториала странице, но ни с чем не сравнивает.
append(nil,l2)=l2
append(cons(n,l1),l2)=cons(n,append(l1,l2)).
Но нужно ли? Программисты уже хорошо выучили селекторный подход и, вероятно, не нуждаются в напоминании для сравнения.
Доклад Тернера продолжается демонстрацией других примеров, в числе прочих и не-решета не-Эратосфена,
primes = sieve [2..]
sieve (p:x) = p:sieve {n;n<-x;n%p>0}
с помощью которого демонстрируют и преимущества Хаскеля на его официальном сайте и сорок лет спустя, в момент написания этих слов.
Завершается лекция Тернера полным текстом стандартной библиотеки KRC в которой демонстраций уравнений с ПМ более чем достаточно. Демонстраций многих современных возможностей, но не обязательно современного вида:
filter f [] = []
filter f (a:x) = a:filter f x, f a
= filter f x
Тернер заявляет, что его опыт аппликативного программирования раз за разом подтверждает, что код на SASL-образных языках на порядок короче, чем эквивалентный код на традиционных языках программирования.
Тернер не приводит никаких сравнений и примеров таких успехов и даже не говорит какой именно порядок имеется в виду. Даже выбранный им пример кода плохого Лиспа не в десять раз длиннее, чем пример кода хорошего KRC.
Небыстрая сортировка
Но, конечно, среди функциональных программистов позднее нашлись желающие подтвердить, что код на ФЯ в 2-10 раз короче. В зависимости от смелости трактовки слова "порядок". Подробность описаний этих подтверждений серьезно варьируется.
Так Вадлер в стенограмме обсуждения одного из более поздних докладов Тернера [Turn84] вспоминает, что написал одну и ту же программу на Лиспе и KRC. Кода на Лиспе получилось 40 страниц, т.е., надо полагать, 1.5-3 тыс. строк. Кода на KRC, вышло 4 страницы.
Наш старый знакомый по рассказу о SKI-машине NORMA Ричардс пишет [Rich85], что лексический анализатор (видимо, часть имплементации ARC SASL?) получается размером в 800 строк на Паскале-образном системном языке мэйнфрейма B1900, 400 строк на Лиспе и только 40 строк на ARC SASL.
Подробнее всего описан один из самых скромных успехов. В 83-ем году Саймон Пейтон-Джонс написал [SPJ85] на SASL генератор парсеров. Получилось 835 строк. Но Пейтон-Джонсу не удалось написать в десять раз больше строк кода на BCPL. Получилась только 1501 строка. Нужно заметить, справедливости ради, что BCPL не особенно многословный язык из-за отсутствия сигнатур типов и довольно легковесного ФЯ-образного синтаксиса. В статье достаточно примеров кода Пейтон-Джонса на SASL (но не полный текст программы), но не на BCPL. Как он писал на BCPL можно посмотреть в статье про сравнение SKI-интерпретатора с SECD [SPJ82].
Но даже такие совсем небольшие примеры - слишком большие для демонстрации в статье о преимуществах ФП. И пример подходящего размера был найден. Во времена первых ФП-конференций он еще не был готов, но вскоре после них начал использоваться для демонстрации краткости функциональных языков. Да, это был так называемый "квиксорт".
Мы уже встречались с его ранними версиями в нулевой части нашей истории. Первоначально, "квиксорт" Берджа-Левенворта не был таким уж немногословным и был вполне сравним с квиксортом на Паскале по числу строк кода. У Ван Эмдена и Тернера он стал несколько компактнее благодаря паттерн-матчингу, но все еще не демонстрацией краткости, а в первую очередь демонстрацией того, что на логическом или функциональном языке вообще можно написать не совсем тривиальную программу.
Свою финальную форму этот "квиксорт" принял только с появлением ЦФ-нотации в языках Тернера. И придал ему эту финальную форму работавший Университете Кента над диссертацией Силвио Мейра (Sílvio Romero de Lemos Meira).
Рассказывая о "квиксорте" Мейры, Тернер ссылается [Turn84] на неотсканированный отчет [Meir83] 83-го года об имплементации сортировки на KRC. Отчет до нас не дошел, но дошло сообщение [Meir83b] Мейры в usenet группе net.applic, от 16 августа 83 в котором есть такой KRC код:
quick [] = [] ;
quick (a:x) = quick {y | y <- x; y <= a} ++
a:quick {z | z <- x; z > a} ;
В стандартной библиотеке [Turn83] новой версии SASL c ЦФ-нотацией от ноября 83-го года "квиксорт" занимает всего-то две строки:
sort () = ()
sort (a:x) = sort {b <- x; b<=a} ++ a : sort {b <- x; b>a}
Квиксорт на Паскале - пара десятков строк. Сокращение кода на десятичный порядок продемонстрировано.
Ричардс [Rich85] сравнивает 18 строк квиксорта на Паскале с "квиксортом" на ARC SASL, который он растянул на четыре строки.
sort [ ] = [ ]
sort (a:x) = sort [b; b <- x; b < a]
++ [a] ++
sort [b; b <- x; b >= a]
Может быть для того, чтоб продемонстрировать то, что преимущества в краткости растет с ростом серьезности программ. Может какие-нибудь игрушечные примеры и короче всего в несколько раз, но посмотрите на лексер. Реальная программа в 20 раз короче! Код реальных программ, правда, не показан.
Разработчик Lazy ML и его компилятора Томас Йонссон в своей диссертации [John87] тоже сравнивает квиксорт с "квиксортом". В Lazy ML не было ЦФ-нотации, так что он просто использовал filter из стандартной библиотеки для получения двухстрочника. Не включил имплементацию фильтра в пример, в отличие от Берджа и Ван Эмдена. Но у Йонссона и квиксорт на Паскале покороче, чем у Ричардса - 15 строк. Только на одну больше, чем "квиксорт" Берджа.
Случай на мосту через поток данных
В том же 81-ом году, когда Тернер и Дарлингтон прочитали свои лекции в Ньюкасле, состоялась вторая ФП-конференция, на которой с их идеями и языками уравнений познакомилась более широкая аудитория.
В октябре 81-го, уже знакомые читателям по предыдущей части, группа функциональных языков и архитектуры Арвинда совместно с группой вычислительных структур Денниса организовали в Портсмуте, Нью-Гэмпшир конференцию по функциональным языкам программирования и компьютерной архитектуре (FPCA). Как и LFP, эта конференция с тех пор проходила раз в два года, только по нечетным годам, пока в 96-ом они не объединились в одну ежегодную и, скорее всего, знакомую читателю ICFP.
Конференция была организована создателями (эмуляторов) специальных машин и они были центральной темой, но нашлось место и для мечтателей о том, у чего не будет такого мрачного будущего.
На первой FPCA 81-го года, скорее всего, присутствовали авторы LML и разработчики его компилятора Йонссон и Августссон. Там они не только увидели доклад Тернера, но и обсуждали с ним имплементацию ФЯ. Этот разговор подтолкнул Йонссона к изобретению G-машины, но, к сожалению, не подтолкнул Тернера к работе над более-менее эффективными имплементациями ФЯ на обычном железе. Это, разумеется, оказало серьезное влияние на то, как развивалась история ФП.
На этой конференции Тернер выступил с докладом "Семантическая элегантность аппликативных языков" [Turn81], в котором продемонстрировал написание и оптимизацию более серьезной программы, чем однострочники, которые демонстрировались до того. Серьезная программа растянулась на пару десятков строк. Сохранилась она не только в статье. Несколько вариантов этого кода поставлялись как примеры вместе с первой имплементацией KRC и её исходными кодами.
Программа строит гомологический ряд парафинов со всеми возможными изомерами. Да, в наборе бенчмарков GHC nofib есть такая программа. Но нет, это не порт KRC-кода на Haskell. В nofib переписанное на Хаскель другое решение той же задачи, которое демонстрировало уравнения с ПМ добавленные в другой язык, о котором мы еще напишем.
Когда программа на языке уравнений с ПМ разрастается аж до десятков строк, в ней начинают встречаться и бросаться в глаза более сложные примеры сопоставлений с образцом, использующие и вложение.
invert [[a,b,c],d,e,f] = [a,b,c,[d,e,f]]
invert x = x
Что может быть важно. Ведь, как мы выяснили в нулевой части, есть серьезные основания подозревать, что некоторые из тех немногих, кому посчастливилось увидеть примеры ПМ в 70-х, даже не поняли, что такое вложение возможно.
На этой же конференции состоялся доклад [Darl81] про планирующуюся параллельную ФП-машину ALICE с примерами на псевдо-HOPE. Да, и тут Дарлингтон использовал примеры без --- разделителей, вместо которых только отступы
MinOfList : List Integer -> Integer
MinOfList(x::nil) <= x
MinOfList(x::y::L)
<= Min(x, MinOfList(y::L))
Псевдокод похож на одну из версий NPL, от которых осталось меньше всего следов, но часто не имеет и обязательных сигнатур с типами. Так что слушатель докладов и читатель статей и в этот раз спасен Дарлингтоном от суровых реалий синтаксиса HOPE, близкое знакомство с которыми навряд ли способствовало бы популярности языков уравнений с ПМ.
В первые годы 80-х уравнения с ПМ используют как язык программирования или псевдокод в статьях только имеющие какое-то отношение к разработке NPL/HOPE и SASL.
Конференция 81-го года дает возможность посмотреть как даже Вадлер, впоследствии знаменитый своими статьями, использующими уравнения с ПМ, еще использует примеры на ISWIM с другой ассоциативностью применения функций (как обычно, в каждой статье свой ISWIM). В статье уже есть ссылки на работы Бурсталла, так что использование Вадлером ISWIM, скорее всего, последнее.
Родственное уравнениям с ПМ направление - алгебраическая спецификация - все еще представлено уже знакомыми нам по нулевой части бывшими разработчиками AFFIRM Гуттагом [Gutt81] и Мюссером [Muss81] и все еще разработчиками SCRATCHPAD [Jenk80]. Но ближайшие исполняемые языки с паттерн-матчингом и "уравнениями" были представлены только Пролог-образными языками [Clar81] и примерами кода вроде таких
mode merge(?,?,^)
merge(u.x,u.y,u.z) <- merge(x,y,z)
merge(u.x,v.y,u.z) <- u < v |merge(x,v.y,z)
merge(u.x,v.y,v.z) <- v < u |merge(u.x,y,z)
где на Прологах часто пишут обычные функции, которые проаннотированы как обычные функции. И может возникнуть вопрос: зачем вообще в таком случае писать на Прологе и смотреть на все эти неиспользуемые отличия от уравнений с ПМ?
После вышеописанных конференций и курсов про уравнения с ПМ знают уже все, кто должен о них знать для того, чтоб в 82-ом году на судьбоносной встрече в лаборатории Резерфорда — Эплтона затянувшаяся предыстория функционального программирования наконец закончилась и началась история.
Лука Карделли и поздняя эволюция NPL
В октябре 1977, в том же месяце, когда Бэкус получил премию Тьюринга, британское агенство SRC (с 81-го года SERC: Science (and Engineering) Research Council) сформировало панель Робертса. S(E)RC распределяло государственное финансирование между британскими проектами о которых обычно рассказывает наша история. И панель Робертса должна была решить, кто получит деньги в тяжелые времена "кризиса программного обеспечения". Который, напомним, заключался в том, что железо дешевеет, а ПО дорожает. Отчет панели вышел в марте 79-го. Ответом на кризис должна была стать Software Technology Initiative (STI).
Наверное, решили в S(E)RC, у академиков или уже есть решения, или, по крайней мере, скоро будут. Но они не доходят до индустрии. Что делать? Нужно проводить больше курсов, на которых академики будут знакомить со своими исследовательскими языками и программами. Нужно создать "общую базу" ПО и железа, чтоб что-то разрабатываемое одними академиками могло быть скомпилировано и запущено другими академиками и не только ими. Общие языки Pascal и FORTRAN 77, общая ОС UNIX, общие рабочие станции PERQ [RAL83] [RAL84].
Pascal, FORTRAN 77 и UNIX выбраны потому, что уже популярны в академической среде. PERQ выбрана под влиянием Хоара и не появлявшегося в нашей истории с начала нулевой части разработчика Лондонского компилятора CPL Кулуриса [PERQ1].
Выбор Pascal и FORTRAN 77 не означал, что SERC боролся с исследовательским ПО на прочих языках и с новыми исследовательскими языками. В SERC планировали организовать разработку совместимых компиляторов для основных машин, причем планировали сделать так, чтоб из Pascal можно было вызвать функцию на FORTRAN 77 из которой, в свою очередь, можно бы было вызвать функцию на Pascal.
Организовывать совещания и курсы должна была Лаборатория Резерфорда - Эплтона (Rutherford Appleton Laboratory). И 17 ноября 1982-го года дошла очередь до встречи разработчиков ML, LCF и HOPE.
Коллекционирование ML-ей
На встрече присутствовали как давние герои нашей истории: Милнер, Бурсталл, Дарлингтон, Хьюз и Майкрофт (один из изобретателей анализа строгости), так и будущие герои, такие как Митчелл. Гордон и Полсон не смогли принять участие, но прислали документ со своими новостями и пожеланиями. Хоар тоже должен был участвовать, но не поучаствовал. Впрочем, он уже сыграл существенную роль в начинающейся на этом собрании истории продвигая PERQ и приняв на работу в Оксфорде Бернарда Суфрина (Bernard Sufrin), научного руководителя Хьюза, который участие в совещании принял.
Заметки [Wads83] о совещании оставил Вадсворт, который после окончания работы над LCF/ML в 78-ом году ушел из Эдинбурга в Лабораторию Резерфорда - Эплтона.
Предполагалось, что участники встречи поделятся своими целями и общими нуждами и расскажут как STI лучше использовать их исследовательские достижения. SERC хотел, чтоб ML, LCF и HOPE заработали на рабочих станциях PERQ и чтоб были организованы курсы по их использованию. Разработчикам ML, LCF и HOPE нужно было придумать, как это может быть осуществлено.
На совещании зачитали послание Гордона и Полсона, подготовленное за пару недель до него [Gord82].
В заметках описаны работы Полсона и Жерара Юэ в Кембридже и INRIA над компилятором LCF/ML о котором мы уже писали подробнее в предыдущей части.
Полсон с Гордоном не горят особым энтузиазмом связанным с продолжением этих работ. Пишут, что они хотят использовать LCF, а не работать над его имплементацией и имплементацией компилятора ML для него.
Во время встречи в лаборатории Резерфорда-Эплтона Полсон планировал находится в Гетеборге, и обсуждать объединение усилий с теми, кто развивает собственную ветку LCF там.
Но если Гордон с Полсоном не очень-то и хотят работать над собственным компилятором, то почему не использовать компилятор Карделли?
Они пишут, что композитные типы данных и мутабельные ссылки в VAX ML лучше, чем в LCF/ML. Так же им нравится производительность кода, который генерирует компилятор Карделли. Но использовать этот компилятор они не хотят.
Компилятор и рантайм еще не доделаны и не готовы для использования. Например, не имплементирован ввод-вывод. Также, Полсон с Гордоном не хотят переписывать весь код на LCF/ML с которым у VAX ML множество мелких но хорошо распределенных по коду отличий. И в это время на LCF/ML написано уже больше LCF кода, чем в 78-ом году, к чему мы еще вернемся. Тем более они не хотят переписывать Лисп-код, который нужно переписывать потому, что у VAX ML нет интеропа с Лиспом, в отличие от их Кембриджского компилятора. Для имплементации LCF на PERQ они рекомендуют SPICE LISP, который имеет будущее потому, что имплементирует Common Lisp. И Common Lisp похож на MacLisp, так что потребуются только минимальные изменения LCF и Кембриджского компилятора ML.
Наконец, Полсон и Гордон недолюбливают VAX ML как язык, называя его "барочным". А что им нравится?
Мэттьюз разрабатывает в Кембридже язык Poly (про который мы уже писали в предыдущей части), производительность имплементации Гордон с Полсоном считают хорошей, со временем можно будет использовать для написания будущих имплементаций LCF. Правда, будущее Poly не ясно, возможно скорое окончание финансирования от SERC. Гордон с Полсоном надеются на то, что Poly и ML могут быть, со временем, унифицированы. Poly может послужить источником идей для расширения системы типов ML.
Но больше всего им нравится HOPE. Ни Полсон, ни Гордон не писали ничего на HOPE, но дизайн языка произвел на них хорошее впечатление. Они настоятельно рекомендуют продолжать его развитие. HOPE - это ML, который "проще и чище".
В каком направлении развивать HOPE? Нужны эксперименты с обработкой исключений, мутабельными ссылками и ленивостью. Также нужно больше экспериментов с отладчиками для таких языков как HOPE и ML.
Что еще нравится Гордону с Полсоном? Идеи Дэвида Тернера. Какие именно они не пишут, пишут только, что "не обязательно только нормальный порядок вычисления". Больше неназванных идей Тернера должны быть использованы для развития языка HOPE, а идеи Карделли нужно использовать в имплементации. Со временем, HOPE с производительной имплементацией как у VAX ML может стать подходящим языком для имплементации будущих систем, таких как LCF.
Доклады прочих участников, по видимому, были похожи на письмо Полсона и Гордона, но пересказаны Вадсвортом сжато.
То, что в этой работе называется "Эдинбургская исследовательская программа" Вадсворт называет "типизированное функциональное программирование происходящее от ISWIM". ML он называет "функциональным языком высшего порядка в стиле ISWIM". Сегодня мало кто считает языки первого порядка функциональными. Но в 82-ом году были еще не так избалованы большим количеством ФЯ, так что записывали в ФЯ все что можно.
ML выделяют из прочих ISWIM-ов полиморфная система типов и абстрактные типы. HOPE - это ML без мутабельности и обрабатываемых исключений, но с паттерн-матчингом и функциями, определяемыми уравнениями, перегрузкой и ленивыми списками.
Тут нужно напомнить, что с отсутствием мутабельности не все так просто. Как мы выяснили в нулевой части, Эдинбургский HOPE позволял писать некоторые функции на POP-2, который поддерживал мутабельность еще как. И в Эдинбурге писали такие функции. Примерно как LCF/ML позволял писать некоторые функции на Лиспе. И как мы выяснили в прошлой, первой части, Лондонский HOPE имплементировали так, что полноценной поддержки (неоднократной) мутабельности нельзя было сделать в принципе.
На совещании вспомнили имплементации LCF/ML на разных Лиспах. В это время имплементация для PDP-10 сначала на Stanford Lisp, а затем на Rutgers Lisp еще работала в Эдинбурге. Но этому PDP-10 оставалось работать только пару лет, перспективы у имплементации неважные.
Другое дело версии для VAX Unix и Multics, которые разрабатывают совместно Кембридж и INRIA. Эти должны пригодится для портирования LCF на PERQ. Участники совещания не обратили внимания на жалобы в письме Гордона и Полсона о том, что они не особенно хотят работать над этим компилятором.
Обсуждают и независимый от предыдущего порт на VAX Unix в Гетеборге - видимо тот самый, который вдохновил чудом вывода типов Августссона делать не очередной SASL, а типизированный ленивый ФЯ.
Cardelli ML (так Вадсворт называет VAX ML) выглядит как идеальный ответ на требования SERC: имплементирован на Паскале и уже портирован на VAX Unix.
Обсудили и имплементации HOPE. О двух из них мы уже рассказывали. Первоначальная эдинбургская на POP-2 для PDP-10 тоже доживает последние годы. Интересно, что никто не рассматривает возможность портировать её на VAX с помощью POP-11. Может быть даже еще и не знают об этой имплементации или не особенно верят в её перспективность.
Бурсталл рассказал о планах по развитию HOPE в Эдинбурге: параметризованные модули и обработка исключений.
Дарлингтон рассказал о работах в Имперском колледже Лондона. Компилятор HOPE на HOPE, который там пишут не подходит для компиляции в FAM. И им нужен, по крайней мере, быстрый интерпретатор HOPE. Для целевого языка есть только эмулятор параллельного компьютера. Так что код на HOPE Дарлингтон с коллегами пишут дистанционно на Эдинбургской машине, которой недолго осталось работать.
Дарлингтон заверяет, что они поддерживают тесную связь с Эдинбургом для того, чтоб не допустить раскола HOPE на несовместимые диалекты. Тут нужно заметить, что в Эдинбурге и в Лондоне из опыта использования HOPE сделали разные выводы и сформулировали разные, часто противоположные пожелания по развитию языка, так что раскол на два диалекта вполне возможен.
Идет работа и над новой имплементацией HOPE на новом месте, правда с участием знакомых уже героев нашей истории. МакКвин в Bell Labs пишет имплементацию HOPE на Franz Lisp. Она транслирует HOPE в коды ВМ FAM Карделли. Но эти коды потом интерпретируются интерпретатором FAM на Franz Lisp, так что, видимо, не очень быстро. Не понятно, почему не использует компилятор своего коллеги по Bell Labs Карделли как бэкенд. Может быть просто руки пока не дошли?
Бурсталл недоволен скоростью исполнения HOPE кода и видит решение в микрокодовом интерпретаторе для ВМ Карделли FAM, в код которой будет транслировать компилятор, который пишет МакКвин в Bell Labs. Но в Эдинбурге рассматривают и другой план - использовать Spice Lisp, разработчики которого собираются использовать микропрограммируемый PERQ как Лисп-Машину. Но у собравшихся нет иллюзий о том, что это решение заработает раньше, чем через несколько лет.
В Эдинбурге Роберт Рэй, один из разработчиков WPOP, имплементации POP-2, которую использовали для разработки первого интерпретатора HOPE, как раз занимается портированием Franz Lisp на PERQ Unix. Перспективность Franz Lisp пока никого не беспокоит. Хотя уже идет работа над Common Lisp и наступление МТИ с Лисп-машинистами на группу Фейтмана. Может считают, что Franz Lisp не сильно от подмножества Common Lisp отличается, а группа Фейтмана еще не полностью разгромлена и Franz Inc. не основана.
Поэтому на совещании заключают, что самый простой путь портирования LCF и HOPE на PERQ - использовать их имплементации, написанные на Franz Lisp для VAX Unix. "Не должно потребовать больше нескольких дней", когда Franz Lisp наконец заработает на PERQ Unix.
Но некоторым исследователям нужен ML без LCF, и чем выше производительность кода, который генерирует такая имплементация - тем лучше. Это исследователи, работающие над тремя проектами. В заметках Вадсворта не говорится, что это за проекты, но из последующих событий мы можем заключить, что Ханна хочет писать на ML доказатель, а Хеннесси с Митчеллом хотят писать имплементацию ML на ML. В следующей части мы расскажем об этих проектах подробнее. Для чего хотел использовать быструю имплементацию ML Суфрин - нам не известно.
Милнер советует (и с ним, в основном, соглашаются), что начать важнее с имплементации ML, которую легко использовать. Чтоб ML быстрее нашел больше пользователей.
К счастью, компилятор ML Карделли и удобнее в использовании, чем LCF/ML и генерирует более быстрый код, чем Кембриджской компилятор. И потому следует именно его использовать как основу. Но тут парой дней не обойтись.
Нужно писать новый генератор кода, сборщик мусора и, возможно, сделать какие-то изменения в коде компилятора на Паскале из-за отличия в диалектах для VAX и PERQ. Эту работу оценили в два человеко-месяца.
Суфрин предложил в среднесрочной перспективе, когда для PERQ будет доступно расширение памяти для микрокода, написать микрокодовый интерпретатор для абстрактной машины Карделли. За одно, можно будет использовать его и для новой имплементации HOPE, которую пишет МакКвин. И которая тоже компилирует в FAM-код. Хеннесси с Митчеллом и Суфрин даже готовы поработать над такой имплементацией.
Собравшиеся согласны, что переписывание LCF на ML Карделли того не стоит, LCF так и останется на Franz Lisp.
Курсы по HOPE, ML и LCF было решено провести летом 83-го в Эдинбурге и Лондоне. К этому времени, решили участники совещания, будет достаточно для них рабочих станций PERQ и будет завершено портирование имплементаций на эти рабочие станции.
На встрече разгорелась дискуссия о том, есть ли вообще смысл в поддержке и ML и HOPE. Не лучше ли объединить их в один язык, сочетающий их сильные стороны? Кто начал эту дискуссию и каковы были мнения всех её участников Вадсворт не пишет. Но пишет, что Милнер сформулировал её итог так: HOPE и ML представляют собой "разные точки спектра возможных типизированных ФЯ". Разные цели привели к тому, что были выбраны отличающиеся компромиссы в дизайне этих двух языков. И оба языка нужно продолжать развивать. Пока еще не ясно, как должен выглядеть окончательный функциональный язык. На данном этапе нужно экспериментирование, а не стандартизация.
Через полгода после подведения этого итога, в апреле 83-го, у Милнера был готов первый черновик "стандарта" [Miln83], объединяющего HOPE и два диалекта ML.
Standard ML 83.4
Робин Милнер не только изменил свое отношение к объединению ML и HOPE. С конца 70-х годов он не уделял особого внимания ML и LCF, занимаясь вместе с Хеннесси семантикой конкурентности. Но теперь решил вернуться к работе над ML. Что же случилось?
Организованное SERC совещание о будущем ML напоминает прошедшее в предыдущем году организованное ARPA совещание о будущем Лиспа. И не так уж удивительно, что оно привело к похожим результатам - новому языку, претендующему на объединение существующих до него диалектов. В случае Common Lisp один из главных инициаторов работы по объединению писал и историю событий. Но не в случае с ML. Позднее Милнер напишет, что разрабатывать язык, объединяющий LCF/ML, VAX ML и даже HOPE, его убедил Бернард Суфрин. Как ему это удалось, правда, не известно. Авторы истории SML попытались разузнать какие-то подробности у самого Суфрина много лет спустя [MacQ20], но уточнили только время, когда переубеждение Милнера состоялось. Это произошло не на заседании в ЛРА, но на встрече Милнера и Суфрина вскоре после него, еще до окончания осени. Вероятно в Йорке.
Попытка объединения ML-ей, вероятно, могла бы состояться и без Милнера, но его участие несомненно оказало на процесс объединения и его результат огромное влияние. Мы можем оценить разницу сравнивая со следующей попыткой объединить ФЯ. Автора ФЯ, вокруг которого планировалось это следующее объединение, не удалось убедить поучаствовать.
Первый стандартный ML, который мы будем называть SML 83.4, но который так не называл его автор, спроектирован в основном Робином Милнером, который советовался с Аланом Майкрофтом. Черновик рукописного описания был готов в апреле 83-го.
Милнер пишет, что Standard ML - временное название. Как и Common Lisp. Но время перейти от временного к постоянному так и не пришло.
Standard ML не предполагается каким-то инновационным. И SML 83.4 таким не является. Цели:
- исправить неверные решения и убрать излишества оригинального дизайна LCF/ML
- добавить то, чего не хватает, а именно ПМ и АлгТД как в HOPE
- определить, какой минимум пользователь может ожидать от имплементации ML
Типы данных HOPE, по мнению Милнера, нужны для того, чтоб доделать, завершить разработку ML наиболее естественным образом.
Милнер перечисляет с чем он связываться не собирается. В SML не будет ленивости, которая есть в HOPE. Но мы выяснили в нулевой части, что Эдинбургские разработчики HOPE, с которым общается Милнер, решили что ленивость не нужна. В отличие от Лондонских. Не будет и системы исключений, позволяющих бросать какие-то значения кроме строк. Только такие, как в LCF/ML. Но нельзя сказать, что уже есть готовое решение для более выразительных, хотя и есть идеи о том, как типизировать. Родственные идеям Дамаша о типизации изменяемых ссылок.
Интересно, что не задолго до этого Милнер писал о дизайне LCF/ML. Эта статья [Miln82] вышла в январе 83-го в том же номере самиздат-журнала Полиморфизм, что и отчет о встрече в ЛРА. Там он пишет, что АлгТД и уравнения с паттерн-матчингом может и слишком новые для языка, который принимает только проверенные фичи. И полиморфных изменяемых ссылок и более развитых исключений как раз не хватает ML для завершенности.
И тут мы переходим к более неожиданной части списка того, что в SML не попадает. SML должен стать объединением LCF/ML и HOPE с VAX ML Карделли, но фичам из VAX ML почему-то не находится места в SML. Полиморфные мутабельные ссылки, рекорды и варианты Карделли в SML не попадают.
Милнер пишет, что не считает что-то из этого неправильным. Но считает, что сбалансированный язык получается и без этого. Все это может быть добавлено потом, как расширение, но в базе этого не будет.
Основное влияние на дизайн SML, пишет Милнер, - это работы Карделли над VAX ML и Бурсталла и др. над HOPE. Но получается так, что Бурсталл придумал то, что в SML добавлено, а Карделли то, что в SML добавлять не нужно. Милнер утверждает, что "многое позаимствовано у Карделли". Но многое ли? На наш взгляд позаимствовано не очень много. Видимо, не только Гордону и/или Полсону не особенно понравился VAX ML.
Милнер для начала определяет минимальное подмножество SML под названием Bare ML. Минимальный синтаксис без альтернативных конструкций. Без мутабельных ссылок и встроенных типов.
При применении функцийf xв LCF/ML сначала вычисляласьf, а затемx, но в VAX ML сначала вычисляетсяx, что позволило Карделли имплементировать более быстрое применение. В новом стандартном ML порядок вычисления не определен. Что можно посчитать редкой уступкой Карделли со стороны Милнера.
Одна из основных конструкций Bare ML - это некаррированная лямбда с несколькими ветвями ПМ как в HOPE (и как, позднее,functionв OCaml и\caseв Haskell)
fun v1. exp1 | ... | vn. expn
в HOPE она выглядела так [Burs80]:
lambda v1 => exp1 | ... | v2 => expn
Матчинг происходит, правда, не как в HOPE, а как в языке Тернера, Прологе и современных ФЯ: результат зависит от порядка паттернов. Одно из отличий ПМ в Bare ML в том, что в случае невозможности сопоставить ни один паттерн, выбрасывается обрабатываемое исключение.
Милнер почему-то приписывает изобретение HOPE-лямбды Алану Майкрофту. Милнер отмечает, что Майкрофт может не согласится с этим. И да, это вполне вероятно. Это лямбда из HOPE, едва ли Майкрофт претендовал бы на её изобретение. Может быть имеется в виду именно сочетание. Лямбды с многоветочным ПМ как в HOPE, но сам ПМ при этом как в SASL?
Вместо \, как в ML-ях до того, ключевое слово fun. И синтаксис изменился не только тут. Синтаксис в новом ML новый, не делается никаких попыток сохранить хоть какую-то совместимость с LCF/ML или VAX ML. И это, на самом деле, новое явление в создании диалектов ML. Те, что появлялись до сих пор, LCF/ML, VAX ML и Lazy ML могли отличаться мелкими деталями в "ядре" языка и не такими мелкими расширениями или исключениями существующих в LCF/ML фич, все равно оставались узнаваемыми ML-ями. Новый Standard ML 83.4 Милнера похож на LCF/ML не больше и не меньше, чем остальные ФЯ о которых мы пишем, не называющиеся ML
| DEC10 ML | VAX ML | STANDARD ML |
|---|---|---|
let z = x+y in |
let z = x+y |
let var z <- x+y; |
let w = z*z |
enc w = z*z |
var w <- z*z |
in |
in |
in |
| ... | ... | ... |
От звездочек для обозначения параметров типов переходим к буквам с ' префиксом. Но конструкторы типов остаются постфиксными 'a ref, как в LCF/ML.
Все конструкторы с одним параметром, но не нужно писать c () в случае если тип этого единственного параметра unit. Для того, чтоб получить больше используются туплы и можно применить конструктор к туплу.
cons of 'a #'a list вместо cons ('a #'a list) как в HOPE для того, чтоб больше походило на речь на английском. | вместо ++ как в HOPE потому, что так в BNF и так разделяются ветки ПМ в лямбдах.
Суммы типов как у МакКарти из LCF/ML в новый ML не попали, только произведения.
Абстрактные типы данных теперь имеют конструкторы, которые можно разбирать паттерн-матчингом. Не автоматически объявляемые селекторы как в LCF/ML и VAX ML. Правда <=> вместо = для объявления абстрактных типов как в VAX ML. Действительно, нельзя сказать, что заимствований оттуда совсем нет.
Но это потому, что "пришло время избавиться от = в объявлениях". В остальных объявлениях вместо = будет <-, но рассматривается и вариант be как в ранних SASL. Не <= как в HOPE потому, что Милнер решает, чтоб это означало только меньше или равно, "чтоб облегчить переход для программистов на Паскале". Не думаем, что это самое крупное препятствие для перехода с Паскаля на HOPE.
BareML расширяется: декларациями инфиксной нотации, ассоциативности и приоритета.
Расширяется мутабельными ссылками. Да, Дамаш уже придумал как делать полиморфное присваивание, но лучше остановимся на мономорфном. В принципе, разрешает Милнер, желающие имплементаторы могут расширить расширение и добавить полиморфную мутабельность. И даже полиморфную рекурсию, если уж на то пошло. Но сам Милнер не собирается этого делать.
Обходить ограничения мономорфных мутабельных ссылок Милнер предлагает так же, как обходят мономорфизм сравнения: передавать мономорфные операции над ссылками в полиморфные ФВП.
И в SML есть перегружаемая проверка на равенство. Но не соответствующие ему констрейнты для параметров типов. Мономорфные операции проверки (не)равенства, которые определены для АлгТД (сравнение структурное) и мутабельных ссылок (равенство указателей).
BareML расширяется конструкцией для описания цикла. Но только одной и не такой выразительной, как в LCF/ML. Вместо всех разновидностей циклов только while.
Милнер не позаимствовал для Standard ML модули. Ни простые, которые уже есть в HOPE, ни параметризованные, которые для HOPE только разрабатывали на основе CLEAR. Можно импортировать файлы с кодом по имени файла.
BareML расширяется функциями ввода-вывода и сериализующими АлгТД в строки и разбирающие строки в АлгТД.
Минимальный набор конструкций Bare ML расширяется в Standard ML 83.4 несколькими конструкциями для удобства программиста, которые определяются однострочным описанием с помощью конструкций Bare ML или уже определенных расширений. Так Standard ML 83.4 есть where-выражение, определенное через let in. case of, определенное применением HOPE-лямбды с ПМ. if then else, определенный через case of, никакого тернарного оператора, как в обоекембриджских языках и LCF/ML.
Литералы для списков как в LCF/ML с ; разделителями.
Каррированные лямбды и декларации именованных функций определенные через базовые некаррированные лямбды. Определения минимальные, но похоже, что нельзя совмещать каррированные формы с многоветочным ПМ. И определения именованных функций несколькими уравнениями с ПМ не разрешены.
Немногочисленные примеры кода написаны в стиле, похожем на стиль в котором написан код на HOPE из [Ryde82]. В случае HOPE это объяснимо тем, что для объявления локальных функций нельзя использовать ничего кроме лямбды с ПМ, но из черновика следует, что у Standard ML 83.4 не должно быть такого ограничения. Некоторые расширения используются, но не синтаксический сахар для каррирования и именованных функций:
infix :: 30 right;
rec data 'a list <- nil | :: of 'a #'a list;
rec var map <- fun f, nil. nil
| f, x::l. f x :: map(f,l)
map (fun x. x + y, [1; 2; 3]) where y <- 2
причем выражение where то ли многократно используется с ошибкой, то ли короткое описание через let не отражает отсутствие необходимости писать var, обязательного в случае базового let.
Булевы операции - обычные функции как в VAX ML, вычисляют оба аргумента в любом случае.
Сильная сторона АлгТД в HOPE в том, пишет Милнер, что они в принципе позволяют определить все встроенные типы. В Bare ML нет предопределенных типов, но в Standard ML 83.4 они есть: unit, bool, Token, int и list. Милнер описал определения для них как АлгТД, которые варьируются от более-менее обычных сегодня для unit, bool и list, до непрактичных чисел Пеано для int и вовсе невозможного определения для Token с бесконечным количеством конструкторов для каждого из возможных сочетаний букв. Предполагается, что имплементатор предоставит эти типы данных с более практичными представлениями. Имплементаторов у Standard ML 83.4, правда, не было. Вскоре на смену ему пришла другая версия.
ПРОДОЛЖЕНИЕ СЛЕДУЕТ
Литература
[Alle78]: John Allen. 1978. Anatomy of LISP. McGraw-Hill, Inc., USA.
[Alle2005]: John Allen. History, Mystery, and Ballast https://international-lisp-conference.org/2005/media/allen-slides.pdf https://international-lisp-conference.org/2005/media/allen-audio.mp3
[Burs80]: R. M. Burstall, D. B. MacQueen, and D. T. Sannella. 1980. HOPE: An experimental applicative language. In Proceedings of the 1980 ACM conference on LISP and functional programming (LFP '80). Association for Computing Machinery, New York, NY, USA, 136–143. DOI:10.1145/800087.802799
[Clar81]: Keith L. Clark and Steve Gregory. 1981. A relational language for parallel programming. In Proceedings of the 1981 conference on Functional programming languages and computer architecture (FPCA '81). Association for Computing Machinery, New York, NY, USA, 171–178. doi:10.1145/800223.806776
[Darl76]: Darlington, J., & Burstall, R. M. (1976). A system which automatically improves programs. Acta Informatica, 6(1). doi:10.1007/bf00263742
[Darl81]: John Darlington and Mike Reeve. 1981. ALICE a multi-processor reduction machine for the parallel evaluation CF applicative languages. In Proceedings of the 1981 conference on Functional programming languages and computer architecture (FPCA '81). Association for Computing Machinery, New York, NY, USA, 65–76. doi:10.1145/800223.806764
[Darl82]: Darlington J, Henderson P, Turner DA, editors. Functional programming and its applications: an advanced course. CUP Archive; 1982 Feb 18.
[Dijk81] Dijkstra, E. (1981). Trip report E.W. Dijkstra, Newcastle, 19-25
July 1981. Dijkstra working note EWD798. https://www.cs.utexas.edu/~EWD/transcriptions/EWD07xx/EWD798.html
[Gord82]: Mike Gordon, Larry Paulson, 1982-11-03 in Polymorphism Vol 1 part 1 Jan 83
[Jenk80]: James H. Davenport and Richard D. Jenks. 1980. MODLISP. In Proceedings of the 1980 ACM conference on LISP and functional programming (LFP '80). Association for Computing Machinery, New York, NY, USA, 65–74. doi:10.1145/800087.802791
[John87]: Johnsson, Thomas. "Compiling Lazy Functional Language." PhD Thesis, Chalmers University of Technology (1987).
[Gutt81]: John Guttag, James Horning, and John Williams. 1981. FP with data abstraction and strong typing. In Proceedings of the 1981 conference on Functional programming languages and computer architecture (FPCA '81). Association for Computing Machinery, New York, NY, USA, 11–24. doi:10.1145/800223.806758
[Hend80]: Henderson, Peter B.. “Functional programming - application and implementation.” Prentice Hall International Series in Computer Science (1980).
[Hoar72]: Hoare, Charles Antony Richard. "Chapter II: Notes on data structuring." In Structured programming, pp. 83-174. 1972.
[Hoar75]: Hoare, C.A.R. Recursive data structures. International Journal of Computer and Information Sciences 4, 105–132 (1975). doi:10.1007/BF00976239
[Hoar22]: Krzysztof R. Apt and Tony Hoare (Eds.). 2022. Edsger Wybe Dijkstra: His Life,Work, and Legacy (1st. ed.). ACM Books, Vol. 45. Association for Computing Machinery, New York, NY, USA. doi:10.1145/3544585
[Huda07]: Paul Hudak, John Hughes, Simon Peyton Jones, and Philip Wadler. 2007. A history of Haskell: being lazy with class. In Proceedings of the third ACM SIGPLAN conference on History of programming languages (HOPL III). Association for Computing Machinery, New York, NY, USA, 12–1–12–55. DOI:10.1145/1238844.1238856
[McJo24]: Paul McJones, John Allen (1937-2022) and Anatomy of LISP https://mcjones.org/dustydecks/archives/2024/04/11/1249/
[MacQ20]: MacQueen, David B., Robert Harper and John H. Reppy. “The history of Standard ML.” Proceedings of the ACM on Programming Languages 4 (2020): 1 - 100.DOI:10.1145/3386336
[Meir83]: Meira, S. R. L. 1983 Sorting algorithms in KRC: implementation, proof and performance. Computing Laboratory rep. no. 14. University of Kent at Canterbury.
[Meir83b]: recursion -- again from net.lang srlm@ukc.UUCP (S.R.L.Meira) (08/16/83) https://usenet.trashworldnews.com/?thread=132780
[Miln82]: Milner, Robin. “How ML evolved.” (1982).
[Miln83]: Robin Milner. 1983. A Proposal for Standard ML (TENTATIVE). April 1983. 25 pages. https://smlfamily.github.io/history/SML-proposal-4-83.pdf
[Muss81]: D. Kapur, D. R. Musser, and A. A. Stepanov. 1981. Operators and algebraic structures. In Proceedings of the 1981 conference on Functional programming languages and computer architecture (FPCA '81). Association for Computing Machinery, New York, NY, USA, 59–64. doi:10.1145/800223.806763
[PERQ1]: PERQ History, 1.3. EARLY DAYS http://www.chilton-computing.org.uk/acd/sus/perq_history/part_1/c3.htm
[RAL83]: DISTRIBUTED INTERACTIVE COMPUTING NOTE 893, RUTHERFORD APPLETON LABORATORY, 3 October 1983 http://www.dataweb.clrc.ac.uk/acd/pdfs/dic/dic841.pdf
[RAL84]: The Software Technology Initiative Final Report 1981-1984
October 1984 http://www.dataweb.stfc.ac.uk/inf/literature/reports/sti_report/p001.htm
[Rich85]: Richards, H. (1985). Applicative programming. Systems Research, 2(4), 299–306. doi:10.1002/sres.3850020409
[Ryde82]: Rydeheard, David Eric. "Applications of category theory to programming and program specification." (1982).
[SPJ82]: Simon L Peyton Jones. 1982. An investigation of the relative efficiencies of combinators and lambda expressions. In Proceedings of the 1982 ACM symposium on LISP and functional programming (LFP '82). Association for Computing Machinery, New York, NY, USA, 150–158. doi:10.1145/800068.802145
[SPJ85]: Jones, S. L. P. (1985). Yacc in sasl — an exercise in functional programming. Software: Practice and Experience, 15(8), 807–820. doi:10.1002/spe.4380150807
[Stee82b]: Guy L. Steele. 1982. Report on the 1980 LiSP Conference Stanford University. August 25-27, 1980. SIGPLAN Not. 17, 3 (March 1982), 22–36. doi:10.1145/947912.1361218
[Stra67]: Strachey, Christopher S.. “Fundamental Concepts in Programming Languages.” Higher-Order and Symbolic Computation 13 (2000): 11-49.
DOI:10.1023/A:1010000313106
[Turn79]: Turner, D. A. (1979). A new implementation technique for applicative languages. Software: Practice and Experience, 9(1), 31–49. doi:10.1002/spe.4380090105
[Turn81]: D. A. Turner. 1981. The semantic elegance of applicative languages. In Proceedings of the 1981 conference on Functional programming languages and computer architecture (FPCA '81). Association for Computing Machinery, New York, NY, USA, 85–92. doi:10.1145/800223.806766
[Turn82]: Turner, D.A. (1982). Recursion Equations as a Programming Language. In: Darlington, John, David Turner and Peter B. Henderson. “Functional Programming and its Applications: An Advanced Course.”
[Turn83]: Turner, D. A. "SASL language manual (revised version)." University of Kent (1983).
[Turn84]: Turner, D. A. (1984). Functional Programs as Executable Specifications [and Discussion]. Philosophical Transactions of the Royal Society A: Mathematical, Physical and Engineering Sciences, 312(1522), 363–388. doi:10.1098/rsta.1984.0065
[Wads83]: Christopher Wadsworth. 1983. ML, LCF, and HOPE. Polymorphism: The ML/LCF/Hope Newsletter I, 1 (Jan.), 5. http://lucacardelli.name/Papers/Polymorphism%20Vol%20I,%20No%201.pdf
[Wadl81]: Philip Wadler. 1981. Applicative style programming, program transformation, and list operators. In Proceedings of the 1981 conference on Functional programming languages and computer architecture (FPCA '81). Association for Computing Machinery, New York, NY, USA, 25–32. doi:10.1145/800223.806759
[Warr77]: David H D Warren, Luis M. Pereira, and Fernando Pereira. 1977. Prolog - the language and its implementation compared with Lisp. In Proceedings of the 1977 symposium on Artificial intelligence and programming languages. Association for Computing Machinery, New York, NY, USA, 109–115. doi:10.1145/800228.806939
[Warr77b]: David H D Warren. 1977. Prolog - the language and its implementation compared with Lisp. Slides https://www.softwarepreservation.org/projects/prolog/edinburgh/doc/slides-ACM1977.pdf
[Whit77]: White, Jon L. "Lisp: Program is Data: A historical perspective on MACLISP." In Proceedings of the 1977 MACSYMA Users' Conference, MIT Laboratory for Computer Science, Cambridge, Mass, pp. 181-189. 1977.
[Whit79]: Jon L. White. NIL: A perspective. Proceedings of 1979 MACSYMA Users' Conference, Washington, D.C., June 1979. https://www.softwarepreservation.org/projects/LISP/MIT/White-NIL_A_Perspective-1979.pdf