История применения и оценки функционального программирования.
=======

- [История применения и оценки функционального программирования.](#история-применения-и-оценки-функционального-программирования)
- [Часть 2: Великое уравнивание](#часть-2-великое-уравнивание)
  - [Синтаксическая элегантность уравнений](#синтаксическая-элегантность-уравнений)
    - [Бегство из MACSYMA](#бегство-из-macsyma)
    - [В Ньюкасл со своими уравнениями](#в-ньюкасл-со-своими-уравнениями)
    - [Небыстрая сортировка](#небыстрая-сортировка)
    - [Случай на мосту через поток данных](#случай-на-мосту-через-поток-данных)
  - [Лука Карделли и поздняя эволюция NPL](#лука-карделли-и-поздняя-эволюция-npl)
    - [Коллекционирование ML-ей](#коллекционирование-ml-ей)
    - [Standard ML 83.4](#standard-ml-834)
    - [Standard ML 83.6](#standard-ml-836)
    - [Карделли против Карделли](#карделли-против-карделли)
    - [Standard ML 83.11](#standard-ml-8311)
    - [Любой принц в Янтаре](#любой-принц-в-янтаре)
  - [Столетняя война (40%)](#столетняя-война-40)
    - [Standard ML 84.7](#standard-ml-847)
    - [Façadisme](#façadisme)
    - [Fasadrenovering](#fasadrenovering)
    - [Standard ML 85.9](#standard-ml-859)
    - [Le ML](#le-ml)
    - [Неравенство уравнений](#неравенство-уравнений)
      - [Edinburgh ML, SML/NJ, ML Kit](#edinburgh-ml-smlnj-ml-kit)
      - [ANU ML](#anu-ml)
      - [Poly/ML](#polyml)
      - [POPLOG ML](#poplog-ml)
      - [Rutherford ML](#rutherford-ml)
      - [Да, fib](#да-fib)
    - [Пираты Кремниевой Долины](#пираты-кремниевой-долины)
    - [Дети Дюны](#дети-дюны)
    - [Отец с атомным сердцем](#отец-с-атомным-сердцем)
  - [Big in Japan](#big-in-japan)
    - [Успели забыть о Прологе больше, чем японцы успели узнать](#успели-забыть-о-прологе-больше-чем-японцы-успели-узнать)
    - [Новая надежда](#новая-надежда)
    - [Граф 0](#граф-0)
    - [Барендрегт против лямбды](#барендрегт-против-лямбды)
    - [Самый известный птеродактиль на Панталасском театре](#самый-известный-птеродактиль-на-панталасском-театре)
    - [Негативное пространство](#негативное-пространство)
    - [День зависимости](#день-зависимости)
- [Литература](#литература)


Часть 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.   
Смотрите сами. Вот Лисп, показывает Тернер: 

```lisp
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` наподобие лисповых в одном и том же языке:

```haskell
fact(0)=1
fact(n+1)=(n+1)*fact(n)
```

```haskell
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)).
```

Но нужно ли? Программисты уже хорошо выучили селекторный подход и, вероятно, не нуждаются в напоминании для сравнения.   
Доклад Тернера продолжается демонстрацией других примеров, в числе прочих и не-решета не-Эратосфена,

```haskell
primes = sieve [2..]
sieve (p:x) = p:sieve {n;n<-x;n%p>0}
```

с помощью которого демонстрируют и преимущества Хаскеля на его официальном сайте и сорок лет спустя, в момент написания этих слов.    
Завершается лекция Тернера полным текстом стандартной библиотеки KRC в которой демонстраций уравнений с ПМ более чем достаточно. Демонстраций многих современных возможностей, но не обязательно современного вида:  

```haskell
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 переписанное на Хаскель другое решение той же задачи, которое демонстрировало уравнения с ПМ добавленные в другой язык, о котором мы еще напишем.   
Когда программа на языке уравнений с ПМ разрастается аж до десятков строк, в ней начинают встречаться и бросаться в глаза более сложные примеры сопоставлений с образцом, использующие и вложение.   

```haskell
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] и примерами кода вроде таких

```prolog
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 таким не является. Цели:   
1) исправить неверные решения и убрать излишества оригинального дизайна LCF/ML
2) добавить то, чего не хватает, а именно ПМ и АлгТД как в HOPE
3) определить, какой минимум пользователь может ожидать от имплементации 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)

```sml
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 не должно быть такого ограничения. Некоторые расширения используются, но не синтаксический сахар для каррирования и именованных функций: 

```sml
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, правда, не было. Вскоре на смену ему пришла другая версия.   

### Standard ML 83.6

Первый черновик описания стандартного ML был, в основном, работой Милнера. Пусть и объединяющего идеи других людей, но самостоятельно решающего какие идеи объединить. Той же весной 83-го работа над новым языком стала более коллективной. Милнер пишет, что обсуждает язык со многими. Теперь даже большая часть идей о том, какие идеи объединять уже не его. А чьи?   
Милнер вспоминает [Miln83b], что написать пропозал его уговорил Бернард Суфрин. Но не упоминает никаких подробностей и не включает (пока что) Суфрина в список авторов SML. Этот список разделен на две части. В второй его части те, кто не участвовал в обсуждении первого черновика, но принимали участие в создании первоначального ML: Локвуд Моррис, Малкольм Ньюи и Крис Вадсворт. Но нет тех, кто работал над NPL, например, Дарлингтон.   
Первая часть списка авторов состоит из тех, кто обсуждал SML с Милнером лично или передал свои идеи. Мы не знаем точно всех обсуждавших SML с Милнером. Уже через пару месяцев, в самой первой записи об этих событиях Милнер пишет, что не помнит кто это был. Но, по крайней мере большинство известно.   
Участники совещания в ЛРЭ может и стали делать то же, что и участники совещания лисперов, организованного DARPA незадолго до того, но SERC не стал делать то, что делало DARPA, не предоставил всем работающим над доступ к электронной почте. Так что авторам SML приходилось больше собираться вместе и писать друг другу с помощью почты обычной. Поэтому ранняя работа над SML имела выраженный географический центр.   
Большинство авторов из первого списка Милнера работало в Эдинбурге вместе с ним. Это Кевин Митчелл (Kevin Mitchell), Джон Скотт (John Scott) и Алан Майкрофт (Alan Mycroft), работающие над имплементацией VAX ML, оставленной Карделли в Эдинбурге [MacQ14]. Этот форк VAX ML называется так же, как назывался VAX ML в его документации [Card82a], пока Карделли работал над ним в Эдинбурге - Edinburgh ML. Майкрофт уже поучаствовал в нашей истории как один из изобретателей анализа строгости.   
Это пользователи и разработчики LCF [Miln82] [Gord2000] Дэвид Шмидт (David Schmidt) [Schmidt], Брайан Монахан (Brian Monahan), Стефан Соколовский (Stefan Sokolowski) [Sokolowski]. Шмидт один из тех, про которого вспоминают, что он не обсуждал SML с Милнером лично [MacQ15]. Другой такой участник - Дэвид Моссес (Peter David Mosses) [Mosses]. Соколовский, Моссес и Шмидт - доктора, которые поработали в Эдинбурге год или два в 82 и 83-ем, Монахан работал там над диссертацией до 85-го года.   
Это авторы, имплементаторы и пользователи HOPE, уже знакомые нам по предыдущим частям: Род Бурсталл, Дональд Саннелла и Дэвид Райдхерд. Но вторая, Лондонская группа имплементаторов HOPE в обсуждениях участия не принимала.   
Так вышло, что в это время работающие в Bell Labs в Нью-Джерси имплементатор ML Лука Карделли и имплементатор HOPE Дэвид МакКвин тоже были в Эдинбурге, судя по воспоминаниям МакКвина [MacQ14] [MacQ20], они не приезжали туда специально для того, чтоб обсудить SML.   
Из Кембриджа приезжали другие наши старые знакомые имплементаторы LCF и ML: Майкл Гордон и Ларри Полсон. Из Франции приезжал новый важный герой нашей истории и новый имплементатор ML Ги Кузино (Guy Cousineau), передававший пожелания от еще одного заочного участника и уже знакомого нам имплементатора ML Жерара Юэ.   
Принимавшие участие в судьбоносном совещании в ЛРЭ от Оксфорда и контактировавшие с Кембриджем и подписанные на почтовые рассылки эмелистов разработчики форка LCF и компилятора Lazy ML из Гетеборга не имели представителей.   
В Эдинбурге, дома у Милнера [MacQ14], состоялись два больших обсуждения по 8-10 человек. Милнеру не особенно понравились дискуссии с большим количеством участников и он пишет, не хочет их больше проводить, считает, что собирать мнения в небольших локальных обсуждениях лучше.   
И между апрелем и июнем 1983 состоялось несколько небольших обсуждений в INRIA, Кембридже, Эдинбурге. Но связующим звеном между ними был не Милнер, а МакКвин, который развернул активную деятельность и старался донести мнения от тех или тем, кто не мог поучаствовать в одном из основных обсуждений и обеспечить, как пишет Милнер, "когерентность". Её сохранение очень беспокоит Милнера. Он торопится принять решения. Потому, что иначе "импульс будет потерян" и потеряны шансы получить "когерентный" дизайн.   
Милнер пишет, что взгляды всех этих новых авторов SML нередко сильно отличались. Но и соглашались они друг с другом по многим вопросам. Милнер "надеется", что те, чьи ожидания SML не оправдал смогут "принять" то, что у них получилось. Так что новый, второй черновик описания "пытается представлять консенсус". Но часть этого консенсуса в том, утверждает Милнер, что хороший язык комитет не разработает. К счастью, SML разрабатывает не комитет. Что может прозвучать неожиданно, если речь идет об SML. Что Милнер имеет в виду?   
Это, по видимому, означает, что может труд и коллективный, но с явным лидером. Скорее, как работа над CPL, но не как работа над Common Lisp, которую направлял "Квинкивират", он же "Банда пяти".   
Это, конечно, не какая-то особенность разработки языка, которая мешает считать, что язык разработан комитетом. Или мешает языку являться языком, разработанным комитетом. Не стоит и преувеличивать желание Милнера направлять разработку.   
Существует более сильный и необычный довод в пользу того, чтоб не считать SML языком, разработанным комитетом. Но к тому, какое желание Милнера, наоборот, не стоит приуменьшать и чем на самом деле является SML мы вернемся позднее. Когда будем писать о временах, в которых все это оказывало более существенное влияние на развитие SML.   
С помощью "не-комитета" Милнер, в июне 83-го подготовил второй черновик описания SML [Miln83b]. Пока писал его, Милнер "убедился, что проблемы ML можно исправить сохранив характер ML". И что из себя представляет этот самый "характер ML"? Опять таки, не совсем ожидаемо, но это HOPE.   

```sml
type rec 'a list == nil | op :: of 'a # 'a list;

val rec map ($, nil)  == nil
      | map (f, x::l) == f x :: map(f,l);

map (fun x. x + y, [1; 2; 3]) where val y == 2 end
```

Делает ли добавление АлгТД и ПМ в любой ФЯ HOPE из этого языка? Нет. Мы еще увидим такую модификацию ML, которая не мешает языку быть узнаваемым ML. И увидим не одну. Даже предыдущий черновик описания SML представляет некоторую альтернативу настолько тотальной хопификации.   
SML 83.4 выглядел более своеобразным языком, в котором в ISWIM-образный язык выражений добавлены АлгТД и паттерн матчинг. Но SML 83.6 довольно обычный в описываемое время язык уравнений.   
К этому добавляется и множество совсем необязательных деталей, характерных для HOPE вроде более тяжелого синтаксиса со множеством ключевых слов и некоторого предпочтения туплов в ущерб каррированию. Объявление каррированных функций с помощью нескольких уравнений "не-комитет" обсуждал, но решил что это не понятно и ненужно. Исключили и каррированные лямбды, которые в 83.4 сосуществовали с лямбдами с многоветочным ПМ, как позднее будут сосуществовать в OCaml. Теперь только одна разновидность лямбд с многоветочным ПМ, как в HOPE. Упрощенная декларация каррированных именованных функций с помощью одного уравнения, правда, осталась.   
Множество авторов и пользователей ML в "не-комитете" не особенно помогло стандартному ML больше походить на ML. Похоже, что многие участники не любят не только VAX ML, но и LCF/ML, включая и многих его авторов. Разумеется, нелюбовь авторов Standard ML к ML не единодушна и те, кому нравится LCF/ML еще заявят о себе позднее.   
Большинство участников обсуждения предпочитают туплы из нескольких элементов как в HOPE `(x,y,z)` неоднородным спискам из пар как до того было принято в ML. Перечислениям через запятую там соответствуют такие конструкции: `(x,(y,z))`. Но не в SML. Там теперь туплы будут как в HOPE, плоские структуры с `n` безымянных полей.   
В LCF/ML и первом черновике абстрактные типы данных были одной из основных конструкций, но Бурсталл и другие придумали энкодинг через АлгТД, которые Милнер называет более мощными. Так что в SML 83.6 абстрактные типы больше не в ядре языка. Это расширение, определенное через обычные АлгТД с одним конструктором, видимость которого ограничена телом АТД.   
Но SML 83.6, конечно, не HOPE - это HOPE 2. Многие отличия от HOPE - это реализация планов Эдинбургских авторов и имплементаторов HOPE, с которыми мы уже знакомы. Вроде императивных фич, таких как мутабельность и исключения. Отказ от поддержки ленивых списков, которые в Эдинбурге посчитали бесполезными. Радикальное сокращение перегрузки, но все еще наличие перегрузки для некоторых операций вроде сравнения. Важное отличие от ML в котором перегрузки не было вообще.   
Другие отличия от HOPE до этого момента в статьях о HOPE не обсуждались, но все равно продвигаются его авторами и имплементаторами. Так, МакКвин продвигает смену ПМ со своеобразного (и, по видимому, своеобразного и из-за особенностей имплементации) на привычный, зависящий от порядка паттернов как в SASL, Прологе и современных ФЯ. Но все равно линейный как в HOPE, переменные не могут повторяться для обозначения равенства как они могут в SASL и Prolog.   
На заседаниях "не-комитета" много обсуждали ограничения ПМ и последовательность сопоставления с образцами. Неназываемые обсуждающие считают, что сопоставление от более конкретного к менее конкретному можно имплементировать эффективнее, хотя порядок слева направо и проще для программиста. Но МакКвин как раз разбирался с имплементацией ПМ для своего компилятора HOPE и убедил Милнера, что эффективную имплементацию можно получить и для порядка слева направо.   
Акцентируем внимание на то, что воплощались планы на будущее HOPE именно от его Эдинбургских авторов и имплементаторов, не Лондонских, у которых совсем другие, часто противоположные планы. Но Лондон не имеет представителей в "не-комитете". Правда, неназываемые участники обсуждения хотели запретить в SML изменяемые ссылки и исключения, но они оказались в меньшинстве.   
Делает ли добавление в HOPE мутабельных ссылок (не таких как в LCF/ML) и абстрактных типов данных (не таких как в LCF/ML) из HOPE ML с элементами HOPE? С точки зрения Милнера - да. Но с нашей точки зрения HOPE, уже в момент своего создания получивший главную особенность и основное нововведение ML - вывод типов Хиндли-Милнера, больше похож на объединение двух Эдинбургских школ ФП-строения, чем Standard ML.   
И NPL/HOPE линейка всегда отличалась от ML переработками синтаксиса, которые потребовали бы редактировать практически каждую строку кода. SML прошел через несколько таких переделок.   
Уже во втором черновике многие детали синтаксиса снова изменились. Милнер не хочет использовать `_` в качестве паттерна, который матчит все. Потому, что можно использовать `_` и в именах. Поэтому в предыдуще черновике вместо `_` использовалось `any`, а в этом используется `$`. Некоторые "не-комитетчики" хотят использовать `,` больше, например не только в туплах, но для списков как в HOPE. Но все равно пока для разделения элементов списка используется `;` как в LCF/ML.   
Выражения `let` и `where` теперь с `end`. "Не-комитет" достаточно много спорит о виде `let` и дополнительных ключевых словах для декларации типов и значений. Но большинство определенно считает, что `val` лучше, чем `var` из прошлого черновика.   
`<-` вместо `=` из прошлого черновика тоже никому не нравится, так что теперь будет `==`. Почему не хотят специальный оператор для сравнения, а не для байндингов? Сколько они собираются сравнений писать? Не понятно. Карделли не против того, чтоб использовать `=` и как сравнения и в синтаксисе объявлений. Пока что эта идея не победила. Может быть потому, что Карделли не против неё.   
Карделли заявлял, что скоро структурные редакторы освободят программистов от заботы о конкретном синтаксисе, так что нужно описывать абстрактный синтаксис, а конкретный только рекомендовать. Но всех остальных конкретный синтаксис волнует гораздо больше и они спорят о нем до озверения, утверждает Милнер.   
Решено, что язык будет полностью специфицирован. Очень важное для дальнейшей истории SML решение. Точнее важно то, что этому решению будут следовать. Как мы увидим в дальнейшем, не все создатели единых ФЯ способны на такое.   
Цели обновленного SML декларируются теми же, что и в предыдущем черновике. Но, на практике, уже сделаны некоторые отступления от его анти-экспериментальной сущности. Исключение сделали для исключений. Теперь в SML исключения, позволяющие бросать любые значения, которые обобщают исключения-строки. В прошлом черновике это делать не собирались.   
Новая система исключений придумана Майкрофтом, с использованием идей Монахана. Да, новая система исключений нигде не испытана, пишет Милнер, мы собирались избегать таких фич, но, вроде бы фича простая, работающая и безопасная.   
Так что некоторые эксперименты возможны. Даже для экспериментов Дамаша с полиморфными изменяемыми ссылками появляется какая-то надежда. В SML 83.6 они не попали, но это уже не исключено в будущих редакциях. МакКвин пообещал разобраться с этим вопросом, пишет Милнер.   
Эксперименты, которые все еще недопустимы - это, разумеется, эксперименты Карделли с рекордами. Этому ход в SML закрыт. АлгТД и ПМ как в HOPE поддерживает большинство участников обсуждений. Милнер пишет, что их можно было бы объединить с системой Карделли, добавив к конструкторам именованные поля. Но объединять не стали. Милнер опасается, что от такого богатства фич у пользователей языка глаза разбегутся.   
Личное участие Карделли в заседаниях "не-комитета" не помогло сделать язык SML больше похожим на VAX ML. Но это не касается его стандартной библиотеки. Библиотеку потоков для ввода-вывода для SML теперь разрабатывает Карделли. Наработки Милнера по вводу-выводу выброшены, и Милнер передумал добавлять в ML перегруженные для любого АлгТД функции `read` и `write` потому, что их имплементация потребует "сложного и деликатного" взаимодействия с компилятором.   
Но, конечно, когда сегодня один из тех (немногих), кто знает Standard ML читает, что ядро этого языка не задумывалось для экспериментирования с фичами, то экспериментальная фича, о которой он немедленно думает - это, скорее всего, не исключения и не рекорды. Это параметризованные модули.   
И, разумеется, модули, не только простые модули, но и параметризованные и первоклассные уже обсуждаются комитетом. Простите, "не-комитетом", конечно же. Модулей нет в LCF/ML, но простые модули есть в HOPE и уже позаимствованы Карделли для VAX ML. Мы также помним, что одна из самых амбициозных идей для следующей версии NPL/HOPE (Эдинбургской, не Лондонской, конечно) - это параметризованные модули на основе CLEAR.   
Так что многие участники "не-комитета" хотят модули в SML, особенно имплементаторы ФЯ МакКвин, Карделли, Митчелл и Полсон, которым они нужны для раздельной компиляции, необходимой для практически полезной имплементации языка общего назначения.   
Но Милнер не хочет модулей. Отказываясь от них он вспоминает о "консолидации" и отказа от экспериментирования. Как будто не делает тут же рядом исключений для экспериментирования. И как будто модули, по крайней мере простые, не проверены уже в HOPE не меньше, чем ПМ и АлгТД.   
Но, конечно, сторонники разных модулей мешают друг другу добавить их в SML. Простые модули как в Hope и MODULA 2, за которые выступает Карделли, не добавляют, чтоб оставить место для параметризованных модулей МакКвина. Не понятно, правда, почему простые модули исключают добавление параметризованных, которые могут стать просто расширением простых. Но у модулей вообще, всех их видов, есть и другие, неназванные Милнером противники.   
Правда, как и в случае с типизацией ссылок по Дамашу, Милнер против модулей только временно. Он не только допускает, но и ожидает, что модули будут добавлены, но не сейчас и не Милнером.   
Милнер считает, что не разбирается в модулях. Писать стандарт с модулями надо тому, кто разбирается в них, имеет опыт использования. И такой стандарт будет через год или два. Чем скорее закончим с описанием SML, тем скорее начнем описывать его дальнейшее развитие - MML (Modular ML). Который, вероятно, будет совместим со всем SML кроме абстрактных типов данных, которые в языке с модулями не нужны - можно регулировать видимость конструктора АТД посредством модулей.   
Но способ раздельной компиляции, который не обязательно является модулями, нужен уже сейчас, для SML.
Для этого используются система директив `spec` для декларации без имплементации. Эти декларации функций и типов в тех файлах, где их используют позволяют проверять типы и компилировать файлы по отдельности. Имплементации этих сигнатур должны быть в окружении в момент загрузки скомпилированного файла.   
Типы в сигнатурах могут быть более общими. Если для АлгТД не используется ПМ и автоматически генерируемое равенство, то декларировать можно только часть конструкторов и "конструкторы" могут быть имплементированы как функции.   
Для объявления синонимов для типов, `deftype` в LCF/ML (или `type` в Haskell) тоже используются директивы. Почему директивы? В SML 83.4 синонимов не было вовсе. Но все "не-комитетчики", которые писали код какого-то заметного размера на ФЯ говорили Милнеру, что они очень нужны. Но даже они по какой-то причине считают их сомнительным хаком, так что они добавлены в язык не как обычная конструкция для объявления типа, а как директива вроде тех, что для раздельной компиляции.   
Итак, процесс стандартизации ML продолжает отторгать идеи Карделли. Но Карделли был "достаточно добр, чтоб принять это" - продолжает хвалить его Милнер. Карделли написал детальный черновик мануала по VAX ML. И "щедро предложил" приостановить работу над мануалом для VAX ML пока описание SML не будет закончено. Но почему Карделли приостанавливает описание собственного языка? Что он "принимает", в чем его жертва, за которую его продолжает благодарить Милнер?   

### Карделли против Карделли

До сих пор типичный ФЯ Эдинбургской программы был языком, определенным имплементацией. И если такой язык и изобретался на бумаге, как ISWIM до того, он либо так и не был имплементирован, либо то, что было позднее имплементировано довольно заметно отличалось, носило другое название и было типичным определенным имплементацией языком.   
Не так с SML. Как Algol 68, SML сначала определен достаточно строго и имплементирован позднее достаточно точно для того, чтоб можно было говорить только о некоторых отличиях между языком и его имплементацией.   
Как и авторы Algol 68, Милнер надеялся [Miln83b], что имплементаторы найдут проблемы в описании и самом языке. В отличие от авторов Algol 68 Милнер надеялся, что это произойдет в ближайшие месяцы и серьезных изменений не потребуется.   
И у Милнера были основания надеяться. Как мы выяснили в предыдущей части, ко времени появления первых черновиков описания SML уже существовало несколько компиляторов ФЯ, и даже нестандартного еще ML, создатели которых проделали уже значительную часть работы нужной для того, чтоб имплементировать ML стандартный.   
МакКвин пишет [MacQ14], что Митчелл, Скотт и Майкрофт, работавшие над форком компилятора VAX ML Карделли в Эдинбурге, начали использовать его для прототипирования дизайна SML после апрельских совещаний.   
Тем временем в Кембридже Гордон посоветовал Мэттьюзу написать компилятор SML на Poly. Чем Мэттьюз и занялся [Matt89].   
Как мы помним, сами Гордон с Полсоном не горели особым желанием имплементировать ML, так что вместо того, чтоб переделывать Cambridge ML в компилятор SML Полсон стал первым пользователем компилятора ML Мэттьюза. Но Poly не так похож на SML как ML, так что ничего удивительного, что его автору хоть и удалось имплементировать SML в ближайшие месяцы, но не в самые близкие.   
Работающие над форком компилятора Карделли в Эдинбурге были лучше позиционированы для того, чтоб быстро сделать компилятор SML, но в описываемое время были заняты его полным переписыванием.   
Поэтому, по всей видимости, первую имплементацию SML и единственную более-менее полную имплементацию SML 83.6 написал Карделли. И даже успел выпустить несколько версий.   
Карделли выпустил последнюю версию VAX ML с достаточно подробным описанием [Card83] 14-го августа 83-го года. Она уже содержала некоторые элементы HOPE-фикации, не только названия конструкторов списков как в HOPE, но и экспериментальные простые модули как в HOPE. Это, конечно, не шло ни в какое сравнение с тем, что произошло дальше.   
Уже в следующем месяце девятого сентября [Card83b] Карделли начал серию компиляторов SML и переработанных руководств пользователя. Эти версии Карделли называл "позициями". Но, в отличие от танцевальных позиций, позиции у Карделли нумеруются с нуля (Pose O).   
Трудно сказать, когда была выпущена первая позиция, в руководстве [Card83c] указана явно неправильная дата - 1-е августа - т.е. раньше, чем нулевая позиция и даже последняя версия VAX ML. Вторая позиция [Card83d] и последняя, (частично) имплементирующая SML 83.6, вышла десятого октября 83-го.   
Разница между этими тремя версиями компилятора и их описаниями незначительная.   
Разница между ними и последним компилятором VAX ML очень значительная. Карделли не добавил SML как дополнительный фронтенд, как делал в это время автор Poly Мэттьюз. Карделли заменил один фронтенд на другой. Просто удалил имплементацию своего собственного языка из своего собственного компилятора. Даже разработчики форка его компилятора в Эдинбурге этого не сделали, так что это еще не конец VAX ML. Но, определенно, конец его развития. Карделли пожертвовал своим основным экспериментом - рекордами и вариантами [MacQ14], которые заменены на алгебраические типы данных как в HOPE. Та самая жертва, за которую его благодарит Милнер в своем черновике.   
Язык, который имплементируют Pose 0/1/2 отличается от SML 83.6, но предполагается, что отличия временные. Карделли пишет [Card83e], что не собирается больше поддерживать имплементацию собственного диалекта ML. Со временем, или его компилятор измениться чтоб соответствовать стандартному ML или стандартный ML изменится, чтоб соответствовать компилятору. Трудно сказать, почему Карделли все еще надеется на второй исход.   
Отклонения имплементации Карделли от SML 83.6 можно разделить на две разновидности [Card83e]. Во-первых, не все эксперименты Карделли с ML закончены. Ввод-вывод частично имплементирует предложенный Карделли новый ввод-вывод для SML. Вместо системы деклараций сигнатур для раздельной компиляции из SML 83.6 в имплементации Карделли простые, непараметризованные модули. Они имплементируют идеи Карделли не полностью и работают не совсем хорошо.   
Проверка типов для изменяемых ссылок осталась такой же как в VAX ML, более обобщенной, чем в черновике описания SML. В компиляторе Карделли осталась и поддержка массивов, которых нет в SML 83.6. Надежды на то, что это все может попасть в SML не считаются безнадежными.   
Некоторые новые эксперименты из SML, зато, в компиляторах Карделли пока что не начались. Компилятор Карделли еще не поддерживает новые исключения, пока что можно бросать только строки как в LCF/ML. Карделли не имплементировал `local` конструкцию из SML. Не имплементированы полностью проверки для нового, перегруженного сравнения.   
Работая над вторым черновиком, Милнер передумал делать порядок вычисления аргументов функции неопределенным и определил его не так как в VAX ML. В новой имплементации SML от Карделли порядок пока тот же, что в VAX ML, т.е. неправильный.   
И, после перечисления таких недоработок в имплементации не самых амбициозных инноваций SML, может показаться неожиданным, что самое крупное изменение SML по сравнению с VAX ML - уравнения с паттерн-матчингом - имплементированы. Интересно, что Карделли, когда пишет эти уравнения с ПМ в своем руководстве пользователя компилятора, ставит разделители между уравнениями не в начале строк, как пишущие код на NPL/HOPE и Милнер в своем черновике, а в конце строк:

```sml
val rec map ($, nil)  == nil | 
        map (f, x::l) == f x :: map(f,l)
```

Такой стиль оформления кода не получил особого распространения в среде программистов на SML, но, как мы увидим в дальнейшем, не будет считаться чем-то немыслимым программистами на родственных языках.   
Итак, уравнения с ПМ наконец имплементированы. В значительной степени. Карделли не имплементировал сопоставления с числовыми и строковыми константами в паттернах. Хотя `case of` в SML 83.6 определяется через применение лямбды с ПМ, предполагается, что это специальный случай для проверки типов. Но, по видимому, это не(до) имплементировано в компиляторе Карделли. Компилятор Карделли не проверяет линейность паттернов, т.е. то, что новые связываемые имена не повторяются. Поведение в случае если они повторяются не определено. Проверка полноты ПМ тоже не готова.   
Но главная часть - компиляция ПМ более-менее современного вида сделана. Теперь и в ML паттерн-матчинг - это не проблема для компиляции, как у имплементаторов языков алгебраической спецификации, а как и в Уорреновском Прологе - решение для получения кода, более быстрого чем Лиспо-образный код с предикатами и селекторами. Решение даже более эффективное из-за линейности ПМ, меньшей мощности паттерн-матчинга, чем в Прологе и в SASL.   
В 83-ем году (в худшем случае в 84-ом, когда Карделли описал свой компилятор) уже не просто рассуждают о том, как это можно было бы сделать, как рассуждали в 70-е, а действительно делают [Card84]. Сопоставление образцов оптимизируется для исключения лишних проверок, и представление АлгТД в памяти становится достаточно компактным, чтоб определенный пользователем список был не хуже специального Лиспового. Дополнительная косвенность из-за МакКартиевского разделения на суммы и произведения больше не требуется:

```
  ┌───┐   ┌───┬───┐   ┌───┬───┐
  │   ├──►│ 1 │   ├──►│ 2 │ 0 │
  └───┘   └───┴───┘   └───┴───┘

```

специальные объекты без служебных полей в FAM-машине, правда, только для пар и троек, более крупные рекорды хранят еще и свой размер в начале.   
Разумеется, это важное достижение стало возможным благодаря существенным наработкам сделанным до того. Карделли не единственный, кто пожертвовал своими собственными экспериментами ради SML. Эта жертва, правда, намного понятнее, чем жертвы Карделли. Потому, что эксперименты просто переехали в SML, экспериментатор получил, по видимому, все что хотел. Этот экспериментатор - коллега Карделли по Bell Labs МакКвин прекратил работу над своим незаконченным компилятором HOPE. И эта работа не пропала даром.   
Идеи о компиляции ПМ появились у МакКвина еще в конце семидесятых, во время работы с Жилем Каном [Card84], с которым МакКвин работал в Эдинбурге в 75-76гг над корутинами для POP-2. С Каном мы уже знакомы по истории dataflow-машин.   
Идеи получили дальнейшее развитие во время работы над первой имплементацией HOPE на POP-2 в 1979-80гг, вспоминает [MacQ22] МакКвин в 22-ом году. Но и в тот раз идея так и осталась идеей, в той имплементации компиляция ПМ так и не была сделана. Компиляция ПМ этим методом появилась впервые в имплементации HOPE на Franz LISP, которую МакКвин писал в начале 80-х в Bell Labs. И эти наработки были использованы Карделли для оптимизации ПМ в его компиляторе SML [Card84].   
Идеи не были опубликованы, так что другому герою нашей истории, не так тесно связанному с разработкой SML пришлось изобретать компиляцию ПМ независимо и он свои работы опубликовал.   
После всех этих лет "дозревания", первое поколение паттерн-матчера МакКвина устарело на следующий же год после первого использования в реальном компиляторе. У МакКвина появились идеи получше.   
Но это уже другие истории других компиляторов.   

### Standard ML 83.11

В ноябре 83-го был готов третий черновик описания SML [Miln83c]. Последний в этом году и первый дошедший до нас не в рукописной форме.   
В предисловии более явно обозначается роль наработок HOPE в исправлении недоработок ML. Оттуда исчезли рассуждения про то, что комитет хороший язык не спроектирует и что SML проектирует совершенно точно не комитет.   
В новом черновике Милнер больше не делит авторов SML на действующих и исторических. Теперь они разделены на два сорта. Основные контрибьютеры: Бурсталл, Карделли, Гордон, МакКвин, Милнер, Моррис, Ньюи и Вадсворт. И "также поучаствовавшие" Кузино, Юэ, Митчелл, Монахан, Моссес, Майкрофт, Полсон, Райдхерд, Саннелла, Шмидт, Скотт и Соколовский. На этот раз Суфрин записан в эту вторую категорию авторов. Еще новые люди в ней: Роберт Милн (Robert Milne) и Филип Вадлер.   
Революционное предложение использовать ПМ-лямбду из HOPE и новая система исключений, как видим, не помогли Майкрофту попасть в основные авторы.   
Главными результатом обсуждений второго черновика, пишет (печатает?) Милнер, было решение о разделении описания SML.   
Двумя самыми обсуждаемыми частями языка о которых меньше всего согласия стали ввод-вывод и раздельная компиляция. Но все разногласия о том, каким должно быть ядро языка, касаются мелких деталей. Так что Милнер концентрирует усилия на описании ядра языка без ввода-вывода и модулей. Тем более, что ни выбор того, как именно будет устроен ввод-вывод, ни какие именно модули будут в ML, практически не повлияет на вид ядра языка, утверждает Милнер.   
Тут можно было бы предположить, что разделение современного SML на язык модулей и язык функций - это результат действия закона Конуэя и дизайн SML воспроизводит структуру "не-комитета", в котором собираются разрабатывать модули отдельно, а ядро языка - отдельно. Но мы уже выяснили в предыдущих частях, что еще в CLEAR, от которого модули МакКвина происходят, уже было явное разделение на язык модулей и язык функций. И оба языка составляющих CLEAR разрабатывали одни и те же люди в одно и то же время.   
Описания ввода-вывода от Карделли и модулей от МакКвина должны быть готовы одновременно с третьим черновиком описания ядра SML и все вместе составят полное его описание.   
Имплементатор может имплементировать все три описания или только часть из них, пишет Милнер, но "надеется", что все три компонента будут приняты имплементаторами.   
Полиморфные изменяемые ссылки все еще считаются недостаточно проверенными временем и Милнер все еще ждет хорошего описания от Дамаша или МакКвина.   
Решение полностью исключить типы как у Карделли в VAX ML, а не совмещать их с АлгТД HOPE Милнер называет трудным.   
В третьем черновике произведение типов обозначается не `#` (как в HOPE), а `*` (не как в HOPE). Сопротивление Милнера преодолено и теперь паттерн, который сопоставляется со всем - это привычное `_` (как в HOPE), а сравнение и связывание имен привычное `=` (не как в HOPE). SML приобретает еще одну фичу HOPE - `as`-паттерн и теряет одну из самых распространенных фич эдинбургских и обоекембриджских языков - выражение `where`.   
Еще одно отступление от / усовершенствование HOPE: теперь можно объявлять каррированные функции несколькими уравнениями

```sml
val rec map _ nil = nil
      | map f (x::xs) = f x :: map f xs 
```

авторы SML придумали как рассахаривать такой код в лямбды и `case` выражение:

```sml
val rec map = fun f . fun l . 
            case (f, l) of
                ( _, nil . nil
                | f, x::xs . f x :: map f xs )
```

Рекордам Карделли ход в SML закрыт, но какие-то рекорды нужны и в SML 83.11 добавили "рекорды", которые, скорее всего, уже знакомы читателю по другому функциональному языку. Такое вот объявление списка

```sml
type rec 'a list = nil | op :: of (hd:'a, tl:'a list)
```

рассахаривается в такой вот код:

```sml
type rec 'a list = nil | op :: of 'a * 'a list
exception hd : unit val hd(x::l) = x | hd(_) = escape hd
exception tl : unit val tl(x::l) = l | tl(_) = escape tl
```

И наш традиционный пример теперь выглядит вот так: 

```sml
infixr 30 ::
type rec 'a list = nil | op :: of (hd:'a, tl:'a list)

val rec map _ nil    = nil
      | map f (x::l) = f x :: map f l

let val y = 2 in map (fun x. x + y) [1; 2; 3] end
```

Третий черновик стандарта вырывается за пределы тесного кружка авторов SML и вращается в несколько более широких кругах подписчиков самиздат-журнала "Полиморфизм". Он опубликован в декабрьском выпуске. Как и обещал Милнер, вместе со статьями описывающими стримы Карделли для ввода-вывода и модули МакКвина. В том же выпуске и руководство пользователя очередной версии компилятора Карделли от 15 ноября 83-го [Card83e]. Теперь предполагается, что период накопления опыта имплементации и использования продлится "год или вроде того". И Карделли не особенно торопится. Конечно, двойные равенства он заменил на одинарные, а `$` на `_`, но менее тривиальные нововведения, вроде декларации каррированных функций несколькими уравнениями Карделли не имплементировал ни в этой "третьей позиции", ни в следующей "четвертой позиции" [Card84b], вышедшей аж пятого апреля 84-го года.   
Не известно, насколько полно имплементировал SML экспериментальный компилятор Мэттьюза на основе компилятора Poly, первая версия которого была готова и передана на испытания Полсону в конце 83-го года [Matt89].   

### Любой принц в Янтаре

Итак, после того, как Карделли выпустил четыре ежемесячных версии компилятора SML, пятую версию он выпустил уже почти через полгода. И шестую не выпустил никогда. Как вспоминает МакКвин [MacQ14], в 84-ом году усилия Карделли по работе над SML были "разбавлены" работой над "другими проектами" чтоб в 85-ом году "полностью иссякнуть" из-за "других интересов". Что это были за проекты и интересы?   
Карделли работал над надежным алгоритмом проверки типов для языка Альбано (Antonio Albano) и Орсини (Renzo Orsini) Galileo [Card85], который планировали имплементировать на основе компилятора VAX ML. Galileo - язык с рекордами и множественным наследованием. И пока Карделли работал над ним, у него появились идеи о том, как его структурные рекорды и варианты из VAX ML можно улучшить [Card84c].   
Как мы помним, от структурности типов данных в VAX ML были одни неудобства. Даже если функция обращается только к полям `a` и `b` ее тип не может отражать только этот факт. Функция типа `(|a:int; b:bool|) -> int` не сможет принимать рекорд с полями, которые эта функция не использует. И нет смысла аннотировать значение, созданное конструктором варианта `[|a=3|]` как `[|a:int|]` - его не разобрать в `case`-выражении, которое разбирает и другие конструкторы. Придется объявлять синонимы для структурных типов и использовать их дальше как алгебраические типы из HOPE, только без удобств вроде вывода типов.   
И первый шаг к исправлению всех этих проблем Карделли сделал решив, что функция, конечно, должна принимать рекорды с полями, которые она не использует, тип рекорда `(a:a, b:b, c:c)` должен быть подтипом `(a:a, b:b)`, тип любого рекорда - подтип `type any = ()`. И тип варианта `[a:a]` должен быть подтипом варианта `[a:a, b:b]`. Вариант `type nothing = []` - подтип любого типа варианта.   
Можно, например, описать тип только для структуры списка 

```
type anyList = rec list. [nil: unit, cons: (rest: list)]
```

и функцию, которая обходит его

```
val rec length(l: anyList): int =
      if l is nil then 0 else 1 + length(rest l)
```

а потом применять её к списку с "полезной нагрузкой" вроде целых чисел с типом

```
type intList = rec list. [nil: unit, cons: (first: int, rest: list)]
```

Аннотировать типы все равно пока что придется вручную, но может быть имплементатор Edinburgh ML Митчелл что-нибудь придумает [Mitc84].   
Обратите внимание на то, что для описания своих идей [Card84c] сначала в отчетах Bell Labs 84-го года, а позднее и в статьях, Карделли использует псевдокод, больше похожий на VAX ML и позаимствовавший у SML некоторые детали, но не уравнения с ПМ как в HOPE или SASL. И естественным образом появляется подозрение, что Карделли переделал свой компилятор ML в компилятор языка уравнений не потому, что его переубедили и научили любить уравнения.   
Эти подозрения находят новые подтверждения в новом языке Карделли Amber [Card86], который он разработал и имплементировал в том же 84-ом году для экспериментов со своими рекордами после того, как для них не нашлось места в SML. Amber и его имплементация [Card86b] описаны в отчетах Bell Labs в сентябре 84-го и июне 85-го, которые позднее, в 86-ом году опубликованы как статьи.   

```
type IntList =
   rec(List) [nil : Unit, cons : {first : Int, rest : List}];

value map = 
    rec(map: (Int -> Int) -> IntList -> IntList)
        fun (f: Int -> Int, list: IntList)
            case list of
                [cons = c] [cons = {first = f(c.first),
                            rest = map(f,c.rest)}]
            otherwise [nil = unity];

value y = 2;

map(fun(x : Int) x + y,
      [cons = {first = 1, rest = 
      [cons = {first = 2, rest = 
      [cons = {first = 3, rest = 
      [nil = unity]}]}]}])
```

Во времена его появления, Amber считался ML-образным, но мы его таковым не считаем. Мы считаем его редким примером языка, который произошел от прото-языка Эдинбургской программы, но утратил один из ключевых признаков - параметрический полиморфизм.   
Карделли не против параметрического полиморфизма в принципе, но пока не знает как совмещать его с полиморфизмом через подтипирование. Карделли не считает, что они несовместимы, предполагает, что наработки автора языка Ponder Фейрберна могут помочь решить эту проблему.   
К имплементации Amber решение не поспело, но решение Карделли нашел. Тут нам уже надо переходить от рассказа о работах более известного другими работами Карделли как раз к тем другим работам которыми он и известен. И это уже другая история.   
Amber - функциональный язык, Карделли пишет об отношениях подтипирования между функциональными типами и об уникальности семейства Galileo/Amber как функциональных языков с полиморфизмом через подтипирование.   
Карделли написал компилятор Amber в байткод интерпретатора на основе FAM на Amber [Card86b]. Интерпретатор работал на Macintosh, персональном компьютере с процессором как на рабочих станциях, но с существенно меньшей памятью. Из-за этого ограничения имплементация Amber и была интерпретатором, а не компилятором в нативный код, а сборщик мусора был компактифицирующим, а не копирующим как в VAX ML.   
Разработчики Standard ML смогли убедить Карделли начать переделывать свой компилятор в компилятор SML, но продолжал работать над имплементацией языка, отчищенного от интересных для Карделли фич он не долго.   

Столетняя война (40%)
---------------------

> Человеческие существа деградируют до состояния животных, когда спорят о конкретном синтаксисе.   
> Робин Милнер, Проект стандартного ML (второй черновик) [Miln83b]   

> Мы знаем, чем это закончилось.   
> Лоуренс Полсон, Воспоминания: от Edinburgh ML до Standard ML [Paul22b]   

После убедительной победы стандартных эмелистов над одним из важнейших и, по-видимому, самым успешным на тот момент имплементатором ML их ждали новые победы. С, как выяснилось позднее, еще более важными последствиями.   

### Standard ML 84.7

Следующая встреча разрабатывающего SML не-комитета состоялась в Эдинбурге 6-8 июня 84-го года. В ней приняли участие эдинбуржцы Бурсталл, Милнер, Митчелл, Саннелла, Скотт. Бывший эдинбуржец, теперь представляющий Bell Labs МакКвин. Полсон представлял Кембридж, INRIA - Кузино, а Корнелл - Джеймс Хук (James Hook) - новый автор SML второй категории. Не-комитет также рассмотрел комментарии от Майкрофта и Кента Карлссона (Kent Karlsson), который суммировал взгляды неупомянутых эмелистов Гетеборга.   
"К сожалению", пишут [MacQ85] МакКвин и Милнер, в очередной встрече комитета не смогли принять участие Карделли, Юэ и Гордон. Но они были представлены своими коллегами.   
На встрече обсуждаются планы о написании учебника, возможно на основе руководства к компилятору Карделли, но ориентирующийся как на образец на вышедший в том же году учебник по Scheme - Структура и интерпретация компьютерных программ.   
Планируют разобраться с описанием формальной семантики. Может Моссес использует свои наработки.   
Согласились, что SML - общественное достояние и кто угодно имеет право его имплементировать.   
Решают, что нужна быстрая имплементация, чтоб "убедить мир в жизнеспособности SML". Очень важно, чтоб SML не приобрел репутацию непрактичного, игрушечного языка, пишут МакКвин и Милнер. Конечно, очень некстати, что автор самой быстрой имплементации SML и, скорее всего, самой быстрой имплементации ФЯ на тот момент отвлекся на какие-то свои проекты и утратил интерес к имплементации SML.   
Нужно разрабатывать и портируемую систему, что-то вроде Smalltalk 80. Системный образ, который смогут загружать несколько имплементаций одной виртуальных машины на разных платформах. Этим как раз занимаются Митчелл и другие, которые в 83-км году в Эдинбурге переписали форк нативного компилятора Карделли в интерпретатор байт-кода FAM.   
Не-комитетчики считают, что первое время хорошая производительность будет несовместима с портируемостью, так что для осуществления этих планов потребуются по крайней мере две имплементации.   
Значительная часть обсуждения посвящена модулям, вернее объяснению МакКвином модулей другим эмелистам. Мы рассмотрим модули позднее, пока отметим только, что запланированная независимость дизайна ядра языка от дизайна модулей уже не состоялась.  
Для синтаксиса модулей нужны точки, так что лучше сократить их использование в синтаксисе ядра языка.   
Милнер предложил заменить точки их отсутствием и требованием к паттернам быть "атомарными". Не думаем, что тут требуется объяснение, потому что это предложение отвергли. Между `..` и `=>` выбрали `=>`, как в HOPE.   
Синтаксис списков тоже сделали как в HOPE, с разделителем `,`, а не `;` как в LCF/ML.   
Эти изменения - очередной шаг к современному виду SML, но не все шаги были к современному виду, были и шаги в другом направлении.   
Поскольку синонимы типов снова стали одной из обычных конструкций для объявления типа (как были в LCF/ML, а точнее как в HOPE потому, что параметризованные), было решено использовать ключевое слово `data` для того, чтоб отличать от них декларации алгебраических типов. Но, скорее всего, не так как вы подумали, а так:   

```haskell
type bool = data true | false
```

Соберем все эти изменения в наш традиционный пример:

```sml
infixr 30 ::
type rec 'a list = data nil | op :: of 'a * 'a list

val rec map _ nil    = nil
      | map f (x::l) = f x :: map f l

let val y = 2 in map (fun x => x + y) [1, 2, 3] end
```

Да, Хаскеле-образных "рекордов" Милнера в SML больше нет. Но фича нужна имплементаторам, которые хотят писать компилятор SML на SML. Поскольку Карделли уже потерял интерес к SML, в ML можно вернуть рекорды без кавычек, типы-произведения с метками в "гармонии" с произведениями без меток. Займется их разработкой МакКвин. Решили, что сначала пара видов рекордов будут расширениями, не частью ядра языка, но интеграция в ядро лучшей из экспериментальных систем рекордов весьма вероятна.   
Не смотря на то, что ядро языка должно разрабатываться отдельно от модулей, МакКвин продолжает генерировать идеи о том, что можно заменить при наличии модулей. Может и генеративные АлгТД как в HOPE не нужны и можно обойтись структурными суммами как у Карделли, а новые, отличающиеся типы будут производиться из них модульными механизмами. Было бы забавно, если бы сразу после того, как Карделли потерял интерес к SML, его бы превратили в VAX ML с параметризованными модулями, но идею посчитали слишком экспериментальной для SML.   
То, что абстрактные типы данных не нужны в языке с модулями решили уже давно, но ядро языка все еще собираются стандартизировать отдельно от модулей и что делать с ними после добавления модулей пока не ясно. Может быть АТД будет просто альтернативным синтаксисом для модуля, а не отдельной конструкцией в SML с модулями.   
В SML добавлены числа с плавающей точкой, а с ними добавляются и новые перегруженные операции. Арифметика теперь тоже перегружена.   
Но это не все, возвращаются перегруженные операции для печати значений, от которых уже отказывались. Добавляются две специальные функции, называемые теперь "type-driven": `makestring` и `print`. `print` - тоже специальная функция потому, что написать полиморфную "type-driven" функцию нельзя, не будет контекста с информацией о типе для `makestring` и требование такого контекста нельзя поместить в сигнатуру. Примерно в это же время Карделли работает над решением этой проблемы, но не для SML, а для своих полиморфных рекордов.   
Милнер подготовил новую редакцию описания ядра языка [Miln84] в следующем месяце, в июле 84-го. В октябре - еще одну редакцию [Miln84c], отличающуюся уточнениями и исправлениями в примерах кода. Например уточняется, что синонимы типов не могут быть рекурсивными, а в примеры с туплами добавлены скобки, которые теперь нужны для того, чтоб отличать их от списков.   
Но SML 84.7 (или 84.10) - это не тот SML, который стал в 84-ом году известен в более широких кругах, чем подписчики самиздат-журнала "Полиморфизм".   
В августе 1984 состоялась очередная конференция по Лиспу и функциональному программированию LFP. Мы не знаем, о каком SML был доклад, но в сборнике докладов конференции опубликовали [Miln84b] ноябрьский черновик прошлогоднего SML 83.11 c Хаскеле-образными "рекордами" и без нового Алгол-68-образного способа объявления АлгТД, что, скорее всего сказалось на его распространенности в дальнейшем. Понятно, что с момента отправки статьи до ее публикации проходит заметное время.   
Но как описание языка помещается в лимит страниц для доклада? Просто: на каждой странице сборника по паре страниц описания, развернутых на 90 градусов. Выглядит не очень хорошо.   
Впрочем, для нашей истории важнее не те изменения, которые были сделаны в SML 84.7, а те, которые делать оказались.   
Конечно, не у всех несостоявшихся изменений были серьезные последствия. Например, некоторые не-комитетчики хотели оба вида комментариев: и скобки и однострочные, но это предложение отклонили. Полсон предлагал определения для операторов вида `infix precedence op = id`, где `id` уже определенная функция. Примерно как намного позднее сделали в PureScript. Этому предложению тоже не хватило поддержки. Обсудили или-паттерны, выяснили, что они никому особо не интересны, но возможен небольшой эксперимент в будущем. Кстати, на этом совещании договорились использовать термин "pattern" вместо "varstruct".   
О предложениях из Гетеборга мы знаем только, что они не любили `as`-паттерны по какой-то причине, но `as`-паттерны из SML не убрали.   
Несостоявшимися изменениями с серьезными последствиями были предложения Ги Кузино, представителя INRIA.   
Кузино и примкнувший к нему представитель Корнелла и Роберта Констебля (Robert L. Constable) против исключения из языка `where`-выражения и хотели его вернуть в SML. И вообще в INRIA и в Корнелле хотели бы SML синтаксис больше похожий на ISWIM и LCF/ML, например `let f x =` вместо `let val f x =`. Некоторые участники обсуждения очень сильно ненавидели `val`, вспоминает Полсон, и до сих пор настаивают на том, что синтаксис SML уродливый.    
Выражение-`where` из SML убрали потому, что если объявить ассоциативность, приоритет и т.д. оператора в нем, то это объявление будет после использования, что плохо для парсера. Также, конструкцию посчитали сложной для программиста. Трудно понять область видимости. И МакКвин с Милнером пишут, что `where` "с сожалением" решили не возвращать в язык.   
`val` добавили для того, чтоб было легче отличать объявление функции от матчинга конструктора и убирать не собирались.   
Но Кузино предлагает не только возвращение в прошлое, он желает и новых для ML фич, выступает за нелинейные паттерны как в SASL и Прологе, хочет писать

```sml
val MP(x ==> y, x) = y
```

В не-комитете SML посчитали, что это плохо для оптимизации ПМ. Можно, конечно, и поэкспериментировать, тем более, что Кузино имплементировал такой ПМ, правда, как и ожидалось, не оптимально.   
Помимо официального отчета МакКвина и Милнера о встрече [MacQ85] есть еще и воспоминания Полсона [Paul22b]. Полсон пишет, что не помнит точно, какую из встреч не-комитета он вспоминает, ту, что была в апреле 83-го или ту, что была в июне 84, но по описанию больше похоже на ту, что была в 84-ом. Вспоминает он это почти сорок лет спустя. Но смутность воспоминаний Полсона компенсируется его желанием обсуждать то, чего отчет МакКвина избегает.   
Из документов, которые нашли и оцифровали историки SML видно, что кто-то побеждает. И понятно кого. Но кто этот победоносный автор, сделавший стандартный ML стандартным NPL? Полсон в своих воспоминаниях называет его имя. Это Дэвид МакКвин.   
И пришло время МакКвину побеждать INRIA. Кузино представил предложения Юэ и все они были отклонены комитетом. У Юэ и МакКвина явно были разные виденья ML, заключает Полсон.   
Полсон неоднократно приводит цитаты неких неназванных знакомых. И одна из них рассказывает о том, что на заседаниях не-комитета "было сложно услышать что-то за грохотом сталкивающихся Эго". И Ги Кузино, представлявший INRIA-эмелистов, вспоминает Полсон, просто не имел подходящего Эго для таких столкновений, был "тихим" и "мягким".   
Жерар Юэ же, по мнению работавшего с ним над компилятором ML Полсона, подходил для таких столкновений гораздо лучше. Юэ бы "отчаянно настаивал на своих требованиях", утверждает Полсон, но Юэ не было на заседании не-комитета и МакКвин добился своего. И Полсон согласен с МакКвином по всем пунктам. Полсону не нравились ни нелинейные паттерны, ни выражение `where`, ни синтаксис LCF/ML. Этот синтаксис Полсон считает смесью идей из ISWIM и странностей, произошедших от неумения имплементаторов ML 70-х парсить, о котором ему рассказал Гордон.   
Но Полсон не считает конкретный синтаксис таким уж важным. Трагедия раскола в том, пишет Полсон, что разногласий по важным принципиальным вопросам не было. И ради предотвращения раскола можно было бы и уступить по ряду не особенно важных вопросов.   
"Французы не получили ничего из того, чего хотели" - цитирует Полсон еще одного своего неназванного знакомого. Мы знаем, чем все это закончилось, подытоживает Полсон. И мы действительно знаем, торжество французского ML над британским ML сегодня не вызывает никакого сомнения. В 22-ом году Полсон считает, что МакКвин выиграл битву, но проиграл войну. Но в 84-ом году такой исход должен был выглядеть не очень вероятным. Полсон называет это совещание "судьбоносным", именно на нем произошел "злополучный раскол", который "создал то, что позднее было названо Caml". Но для того, чтоб Standard ML стал, по словам Полсона, "трагически упущенной возможностью" не достаточно создать Caml. Caml создала небольшая оппозиция к более многочисленному движению, развивающему несколько имплементаций. Чтоб Caml стал для него угрозой, что-то в этом движении должно было пойти не так. И у разгромившего французов на судьбоносном заседании МакКвина есть идеи на этот счет. Но это уже другая история.   

### Façadisme

Констебль и прочие разработчики Nuprl в Корнелле, неудовлетворенные направлением развития SML, просто продолжили использовать и поддерживать форк Cambridge ML 4.3 [Nuprl94], имплементирующий LCF/ML в практически первозданном виде. Так этот язык пережил многие более новые функциональные языки и дожил до наших дней.   
Но в INRIA участники проекта Formel не хотели использовать LCF/ML, они хотели использовать такие фичи HOPE как паттерн-матчинг и алгебраические типы данных. Но чтоб у всего этого была LCF/ML эстетика.   
Когда Полсон пишет, что в результате "раскола" получился Caml, читатель скорее всего подумает про OCaml и будет обескуражен тем, что OCaml не так и похож на LCF/ML, не имеет выражения `where` и нелинейного паттерн-матчинга. Но OCaml - не первый и даже не второй язык, который получился в результате этого самого "раскола".   
Первый получился после того, как летом 84-го Ги Кузино добавил ПМ и АлгТД в Cambridge ML [HOL88].   
Эти изменения не привели к изменению названия, язык продолжили называть ML, указывая версии Cambridge ML с новыми фичами 5 (скорее всего) и 6 (это уже точно).   
Не убирая из языка обычную, каррированную ML-лямбду `\p1 p2. exp`, Кузино добавил некаррированную, поддерживающую несколько ветвей HOPE-лямбду `fun C1 p1. exp1 | C2 p2. exp2`, оставив при этом точку разделителем между паттерном и телом функции. Добавил и `case`-выражение   

```
case x of 
      (C1 p1) . exp1
    | (C2 p2) . exp2
```

Уравнения с несколькими ветвями Кузино добавлять не стал, так что получившийся ML остался чистым языком выражений и выглядел скорее как придуманный Бурсталлом в конце 60-х ISWIM с паттерн-матчингом, а не как разработанные им в последующие пятнадцать лет языки уравнений.   
Объявления алгебраических типов данных продолжили использовать те же ключевые слова, что и объявления синонимов типов, `|` достаточно, чтоб их отличить:   

```
lettype T = C1 of T1 | C2 of T2
```

Весь остальной синтаксис остался неизменным, ничего похожего на множество мелких отличий как у VAX ML Карделли и уж тем более переделывания синтаксиса почти с нуля как в SML. Язык получился примерным надмножеством LCF/ML, все инновации его только расширяли:   

```sml
rectype * list = nil | $. of * # * list;;

letrec map f = fun nil . nil
                 | (x.xs) . f x . map f xs;;

map (\x. x + y) [1; 2; 3] where y = 2;;
```

Использование этой модификации Cambridge ML не было ограничено INRIA или прочим анти-SML-сопротивлением, на этом языке стали писать и другие пользователи Cambridge ML, например Гордон, который, судя по посланию, зачитанному на встрече в ЛРА, положительно относился к HOPE.   
И использование Cambridge ML продолжилось, тем более, что замена его на компилятор Карделли не состоялась, а все прочее требовало еще больше работы для доведения до состояния, пригодного для использования.   
Но в INRIA замену для него стали готовить уже в том же 84-ом году. У французских эмелистов было много идей и сами они объясняют раскол не привязанностью к синтаксису LCF/ML, а сомнениями в том, что им удастся добавить в SML нужные им новые фичи.   
Привязанность к синтаксису LCF/ML явно сыграла свою роль, вид обновленного Cambridge ML это убедительно демонстрирует. Но современный вид OCaml, в свою очередь, демонстрирует уже то, что привязанность к синтаксису LCF/ML со временем ослабела, а новых фич, за добавление которых в SML пришлось бы бороться с сомнительными перспективами - было довольно много.    

### Fasadrenovering

Cambridge ML не был единственным LCF/ML, который подвергся HOPE-фикации. Скорее всего, не был и первым. Потеряв надежду на то, что смогут повлиять на решения SML-не-комитета, участники проекта Formel в INRIA оказались в том же положении, что и другая команда разработчиков компилятора ФЯ, которая не имела надежды на такое влияние с самого начала.   
Речь идет о разработчиках Lazy ML и его компилятора - Леннарте Августссоне и Томасе Йонссоне. На очередной ФП-конференции LFP, состоявшейся в Августе 84-го в Остине, Техас, Августссон представил новую версию Lazy ML.   
Августссон с Йонссоном, по видимому, не горели особым желанием изобретать собственный синтаксис, потому и взяли подмножество LCF/ML. Но теперь оказались в ситуации, в которой были вынуждены его изобретать.   
Конечно, авторы и имплементаторы Lazy ML все равно могли основывать свою работу только на подмножестве SML, как до того - на подмножестве LCF/ML. Они не знали как совместить исключения и изменяемые ссылки с ленивым языком. Но подмножество какого именно SML им делать? Каждые несколько месяцев появляется новый SML.   
Августссон с Йонссоном добавили фичи HOPE в свой ML довольно рано, в конце 83-го или начале 84-го года. И, как и их французские коллеги, рано начали использовать свой язык для написания кода. Так что можно предположить, что ни переписывание компилятора и компилируемого им кода раз в полгода из-за очередного полного переделывания синтаксиса SML, ни ожидание годами того момента, когда переделывание синтаксиса SML наконец закончится, не должно было выглядеть для них очень заманчиво.   
Все что им оставалось - добавить в свое подмножество LCF/ML алгебраические типы и паттерн-матчинг своим способом.   
В отличие от французов, они добавили в LCF/ML не многоветочную HOPE-лямбду, а функции, определяемые группами уравнений как в SML [Augu84]. Матчинг зависит от последовательности: слева - направо, сверху вниз как в языке Тернера и в Прологе. Неполное покрытие паттернов обнаруживается, но разрешено. В LML нет обработки исключений, если значение будет таким, которое неполный набор паттернов не сможет обработать - исполнение программы прекращается.   
В отличие от авторов HOPE и подобно INRIA и авторам SML они добавили еще и Бурсталл-`case`-выражение из 60-х. И сделали именно `case`-выражение основной конструкцией через которую выражаются все производные. Что, полагаем, более привычный подход сегодня, чем определение всех ПМ-конструкций через лямбду с ПМ как в прото-SML.   

```sml
case x in 
       C1 p1 : exp1
    || C2 p2 : exp2
end
```
  
Еще один вариант `case`-выражения, не в точности как у Бурсталла, в SML или французском Cambridge ML, с новым видом разделителя между уравнений - `||`.   
Лямбды с такими разделителями в LML нет, но та лямбда, что в LML есть, хотя и похожа на LCF/ML лямбду на первый взгляд, не поддерживает компактное объявление каррированных функций. Так что тут нет выбора между поддержкой каррирования или многоветочного паттерн-матчинга, лямбда в LML просто хуже, чем любая из двух обычных их разновидностей. Упрощенная декларация каррированных функций с помощью уравнений с ПМ, правда, поддерживается.   
Августссон пишет [Augu85], что ПМ в LML развивался под влиянием HOPE и языков Тернера независимо от SML и "пока еще" отличается. Возможно, что это "пока еще" указывает на какие-то планы сделать LML более похожим на SML, которые так никогда и не материализовались. Но некоторые детали синтаксиса ПМ уже выглядят так, как будто позаимствованы у ранних версий SML, например `$`-уайлд-кард и `as`-паттерн. Со временем, правда, уайлд-кард в LML, как и в SML, сделают более привычного вида.   
Есть и ПМ-фичи отсутствующие в SML, а именно гарды. Но гарды не такие как у Тернера в KRC 

```
f x = r1 , p
    = r2 
```

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

```
f x & p = r1
f $     = r2 
```

но не совсем привычные, без возможности пропустить имя функции и паттерны-параметры, которая обычно есть в ФЯ сегодня:

```haskell
f x | p         = r1
    | otherwise = r2 
```

Августссон пишет, что гарды могут быть средством имплементации нелинейных паттернов, но нелинейные паттерны в LML, по видимому, не добавил.   
Уайлд-карды, `as`-паттерны и гарды, правда, появляются уже в более поздних статьях 85-го года, например в докладе [Augu85] на конференции FPCA 85, в котором Августссон более подробно рассказывает о компиляции паттерн-матчинга. Как компилировать паттерн-матчинг Августссон придумал может и не раньше МакКвина, но раньше опубликовал. Потому, что МакКвин не особенно торопился с публикацией. Изобретать самостоятельно компиляцию ПМ авторам LML пришлось не только потому, что наработки МакКвина были мало известны даже подписчикам самиздат-журнала "Полиморфизм", но и потому, что компилировать ПМ для ленивого языка с гардами нужно было другим способом.   
Наш традиционный пример на обновленном LML.   

```haskell
nonfix "_[]";
infixr "_.";
type rec List *a = [] + *a . (List *a);

rec map $ [] = [] 
||  map f (x.l) = f x. map f l;

map (\x. x + y) [1; 2; 3] where y = 2
```

Реальный библиотечный `map` отличается тем, что не использует `$`.   
Как видите, синтаксис для декларации АлгТД в LML тоже оригинальный, не похожий в точности на тот, что в HOPE или ML-ях. Но больше похожий на тот, что в HOPE.   
Но главное отличие АлгТД в LML от тех, что в SML, не в синтаксисе. В SML конструкторы могут либо не иметь параметра вовсе, либо иметь один параметр. Для конструирования объекта кучи со многими полями нужно использовать туплы. В LML конструкторы могут иметь более одного параметра-поля потому, что LML - ленивый язык и конструктор со многими полями вычисляется не так как конструктор с одним полем-туплом. Конструктор с несколькими полями, правда, не обязательно будет конструировать один объект в куче.   
Представление списка чисел в памяти [John86] выглядит примерно настолько хуже VAX-ML-представления, насколько можно ожидать от ленивого языка.

```
                                               
 ┌───┐   ┌───┬───┬───┐   ┌───┬───┬───┐   ┌───┐ 
 │   ├──►│C12│   │   ├──►│C12│   │   ├──►│C00│ 
 └───┘   └───┴─┬─┴───┘   └───┴─┬─┴───┘   └───┘ 
               │               │               
               │  ┌───┬───┐    │  ┌───┬───┐    
               └─►│C01│ 1 │    └─►│C01│ 2 │    
                  └───┴───┘       └───┴───┘    
                                               
```

Лениво вычисляющиеся числа требуют своих объектов в куче и каждый объект требует указатель на функции, который работает и как тег. Но более сложные АлгТД могут иметь представление, которое намного хуже.   
Дело в том, что первоначально Lazy ML был ленивым LCF/ML, в котором нет АлгТД и все типы данных нужно собирать из пар (троек в куче). Отсутствие необходимости в прочих конструкторах привело к выбору имплементирующего ленивость представления в памяти, которое отличается от, например, представления в GHC-Haskell, в котором АлгТД были с самого начала. В LML все ленивые конструкторы должны были помещаться на месте конструктора применения - тройки указателей - соответствующего конструктору АлгТД с двумя параметрами. Так что конструктор с тремя параметрами становился в куче тройкой со ссылкой на тройку, а конструкторы с большим числом - тройкой со ссылкой на массив ссылок, хранящий свою длину в одном из полей. Даже такое представление появилось не сразу, первоначально единственным решением был, по видимому, список троек.   
Другое ограничение не было настолько же вынужденным и сложившимся исторически, но тоже происходящим от особенностей имплементации. Тегом конструктора является не число, которое можно сравнить с числом, а ссылка на набор функций. Авторы LML посчитали, что в АлгТД обычно не так много конструкторов и не нужно создавать слишком большой набор готовых конструкторов с разными тегами. Достаточно конструкторов для пяти значений тегов. Если у типа больше конструкторов - представление в памяти будет примерно как в раннем VAX ML: отдельный объект в куче хранит значение тега и ссылку на следующий объект кучи с полями конструктора.   
Одна из общих фич LML и первых версий SML, из тех, что заметно повлияли на то, как ФП выглядит сегодня, не имела отношения к паттерн-матчингу и АлгТД. Как и в первых SML, раздельная компиляция в LML требовала от программиста декларировать используемые функции, конструкторы и типы. Например, для использования `map` нужно написать 

```
import map: ((*a->*b)->((List *a)->(List *b)));
```

Разумеется, такой подход придумали не авторы SML, но, наверное, они сыграли какую-то роль в нормализации такого в ФЯ середины 80-х. Конечно, писать такое вручную всякий раз программистам не очень хочется. Как мы уже выяснили в прошлой части, компилятор LML писали как инструмент UNIX-экосистемы и к решению проблемы подошли как там было принято. Компилятор генерировал для экспортов в `.m` файлах c LML-кодом заголовочные `.t` файлы с соответствующими импортами, после чего использующий их программист мог вставить их в свой файл с кодом с помощью C-препроцессора. И такое широкое использование C-препроцессора запустило последовательность событий, к результатам которой мы еще вернемся позднее.   
После докладов на ФП-конференциях 84-го и 85-го годов о LML [Augu84] [Augu85] [John85] и VAX ML [Card84] то, как можно имплементировать практичные ФЯ или, по крайней мере, где искать информацию об этом, стало более-менее широко известно в узком кругу ФЯ-имплементаторов.   

### Standard ML 85.9   

Очередной большой съезд не-комитета SML состоялся в Эдинбурге в конце мая 1985 [Harp85]. Эдинбург на нем представляли Милнер, разработчики HOPE Бурсталл и Саннелла, работающие над Edinburgh ML (форком компилятора Карделли) Митчелл и Скотт, а также три новых героя нашей истории: имплементатор SML Дэвид Берри (David Berry) и два более важных деятеля, Роберт Харпер (Robert Harper) и Мадс Тофте (Mads Tofte), появление которых знаменует начало новой главы в истории ML.   
Еще трое поработавших когда-то над ML и/или HOPE в Эдинбурге представляли уже другие группы разработчиков. Один из основных авторов HOPE и теперь SML МакКвин, работающий в Bell Labs вместе с Карделли, который кстати вернулся к обсуждению SML после перерыва чтоб потерять последние остатки интереса к SML. Майкрофт теперь представлял эмелистов Кембриджа вместе с Полсоном и автором Poly Мэттьюзом. К работе над ML после долгого перерыва вернулся и Вадсворт, работающий в лаборатории Резерфорда - Эплтона.   
Во встрече не-комитета поучаствовал некий Ник Шарман (Nick Sharman) от Software Sciences. Не уверен, что мы еще о нем услышим после этого.   
Не-комитет ознакомился еще и с письмом с комментариями от Дэвида Парка, того самого, который уже поучаствовал в нашей истории как не самый успешный имплементатор LISP и CPL. Харпер составил и описание этого заседания не-комитета.   
Харпер, Мэттьюз и Парк поучаствовали в разработке языка достаточно, чтоб попасть в список авторов SML второго класса [Miln85].   
Как обычно, значительная часть обсуждений была посвящена параметризованным модулям МакКвина, которым мы до сих пор не уделяли особого внимания потому, что пишем историю имплементаций и имплементаторы SML и родственных языков в это время активно работают над имплементацией ПМ и АлгТД, но история имплементации МакКвиновских модулей еще как следует не начиналась. Но это все скоро изменится. В 85-ом году Харпер начал работать над имплементацией модулей в Edinburgh ML и мы рассмотрим историю модулей подробно в следующей части.   
Другая тема с большим будущим - перегрузка. На этой встрече Майкрофт выступает за более универсальный и доступный программисту механизм перегрузки, чем просто перегрузка арифметики для ограниченного числа типов и операций сравнения для менее ограниченного числа типов. У Майкрофта есть несколько сторонников, но голосование он проиграл.   
В очередной раз обсудили полиморфные изменяемые ссылки и в очередной раз решили, что они не готовы. МакКвину не нравится подход Дамаша, считает его ограниченным.   
Карделли предложил отказаться от локального объявлений типов. Прочие не-комитетчики признали, что никогда не использовали локальные типы сами, но решили оставить их в SML.   
На этой же встрече МакКвин пересказал свое предложение по дизайну рекордов и Милнер предложил решить ряд вопросов:   

1. Использовать ли именованные конструкторы рекордов как в Хаскеле и в рекордах Милнера. Они позволили бы меньше аннотировать типы, но достаточно единодушно решили, что их в SML не будет. 
1. Функции-селекторы, как в Хаскеле и в рекордах Милнера. Вадсворт против селекторов и было решено, что селекторов не будет. Программист, которому понадобятся селекторы может их и сам написать.   
1. Именованные поля в конструирующих выражениях и в паттернах. Рекорды будут скорее не как в предложении Милнера, а как у Карделли в VAX ML.   
1. Перегрузка имен полей в рекордах. Милнер за перегрузку полей. И перегрузка полей будет.   
1. Значимость порядка и приведение между рекордами с именованными полями и с безымянными (туплами). Порядок в выражениях имеет значение - определяет последовательность вычислений - но не в паттернах.   
1. Ключевые слова для вызовов. Нет селекторов - нет проблем.   
1. Специальные скобки и символы. Скобки решили делать `(| |)` как были сделаны у Карделли в VAX ML, а `#` в начале имен полей `#foo` не нужно.   
1. Имена полей в типах. Будут.   
1. Что будет основной формой, а что - производной. Туплы - производная форма. Это рекорды с полями, названными по их порядковому номеру.   
1. Полиморфизм и подтипирование рекордов. Милнер против, считает что эти проблемы еще не решены. И потому такого в SML не будет. А значит, что перегрузка полей будет такой же ограниченной как и вся прочая перегрузка в SML в это время.   
1. Можно ли писать `(| x |)` вместо `(| x=x |)` в паттернах? Карделли заявил, что это он изобрел такой синтаксис и он ему больше не нравится. Решили, что так делать нельзя.   

Получилось так, что Карделлиевские рекорды из VAX ML попали таки в SML. Но, справедливости ради нужно отметить, что принятие не-полиморфных рекордов в SML с самого начала, скорее всего, не решило бы проблему потери Карделли интереса к имплементации SML. Принятие на этом этапе определенно не решило. С не-полиморфными рекордами он уже поэкспериментировал до того.   
Кто-то предложил добавить и Карделлиевские не-полиморфные варианты, но не-комитет против, включая и самого Карделли.   
У многих авторов и имплементаторов ФЯ, в числе прочих и SML, позднее будут другие мнения по всем этим рекордо-вопросам. Но пока что, судя по описанию заседания, все эти важные решения дались не-комитету относительно легко и похоже, что большинство не-комитетчиков не имело какого-то сформировавшегося и важного для них самих мнения по всем этим вопросам.   
Что им дались значительно тяжелее? Разумеется очередное переделывание синтаксиса. По этим вопросам хорошо сформировавшееся мнение было у многих.   
Карделли предложил сделать все, что называется буквами префиксным, а символами - инфиксным. Не-комитетчики оценили простоту предложения, но все равно единодушно отклонили.   
Милнер хочет заменить `type rec` на `data`, а `val rec` на `fun` и, соответственно `fun` для обозначения лямбды на `fn`. Дальнейшее осуждение Харпер описывает фразами вроде "общее недовольство и несогласие", "в этот момент дискуссия стала непродуктивной".   
Не-комитет дал решительный отпор Милнеру и постановил, что разобраться с тем, как будет выглядеть синтаксис должен под-не-комитет по синтаксису.   
На встрече сформировали три под-не-комитета. По вводу-выводу, которым занимался когда-то Карделли, пока не перестал, в составе: Харпер, МакКвин, Мэттьюз, Митчелл. По раздельной компиляции: Харпер, МакКвин, Мэттьюз, Митчелл. По синтаксису: Харпер, МакКвин, Скотт.   
Позднее в том же году под-не-комитет по синтаксису принял предложение Милнера. А Карделлиевские составные скобки рекордов `(| |)` заменили на скобки комментариев `{ }`, а скобки комментариев наоборот стали составными `(* *)`. Так что "ядро" SML в сентябрьской редакции описания [Miln85] наконец приняло вид, похожий на современный:   

```sml
infixr 5 ::
datatype 'a list = nil | op :: of 'a * 'a list

fun map _ nil    = nil
  | map f (x::l) = f x :: map f l

let val y = 2 in map (fn x => x + y) [1, 2, 3] end
```

На этом история адаптации изобретений 70-х закончилась и началась история формального описания Standard ML и решения проблем, которые были в 70-х в основном только сформулированы: разработка и имплементация параметризованных модулей, перегрузки и интеграции изменяемых ссылок в ФЯ. Но это уже другая история.   

### Le ML

В том же 84-ом году, когда Кузино добавил в Cambridge ML паттерн-матчинг и АлгТД, в INRIA начали работу над более амбициозной имплементацией ML [Maun86]. На этот раз ML не стали транслировать в Лисп. Le Lisp считается хорошей имплементацией Лиспа, но его компилятору нужно пытаться компенсировать проблемы Лиспа с производительностью, вроде особенностей (отсутствия) типизации, которых в ML просто нет. Так что решено использовать виртуальную машину LLM3, которую Le Lisp использует для облегчения портирования. Она достаточно низкоуровневая для этого.   
Из-за использования рантайма и бэкенда Le Lisp новый компилятор сначала называли Le ML. Позднее его стали называть CAML по имени другой виртуальной машины уровнем выше [Cous90].   
Уровнем выше над LLM3 в новой имплементации ML - виртуальная машина CAM (Categorical Abstract Machine) [Cous87]. Почему "categorical"? Набор её инструкций основывался на исчислении категорных комбинаторов Курьена (Pierre-Louis Curien). Кузино посчитал, что набор инструкций на основе формализма поможет доказывать корректность оптимизаций.   
Как основные операции тернеровского SK-интерпретатора соответствуют инстансу `Applicative` для функций, основные операции CAM соответствуют операциям из Хаскельного модуля `Control.Arrow` над функциями и парами вроде `(<<<)` и `(&&&)`. Но главное отличие CAM от комбинаторного интерпретатора в том, что она-то не комбинаторная.   
CAM собирает окружения из пар указателей. Как мы выяснили в предыдущих частях, имплементаторы ФЯ или хотя-бы мечтали, как Стил, или даже успешно смогли, как Карделли, отказаться от такого подхода и сделать окружение массивом, чтоб оптимизировать время доступа к нему. Но Кузино и др. считают, что лучше оптимизировать конструирование замыкания. И новые развесистые окружения-деревья из пар быстрее склеивать из уже имеющихся конструированием пар. По крайней мере асимптотически.   
Быстрое конструирование замыканий, например, частичных применений, посчитали авторы новой виртуальной машины, лучше подходит для функционального программирования вообще и для имплементации ленивости в частности. Помимо компилятора строгого по умолчанию языка Le ML/CAML, над которым работал Аскандер Суарес (Ascander Suarez), Мишель Мони (Michel Mauny) писал и компилятор ленивого ФЯ Le LML/Lazy CAML. И даже в строгом по умолчанию языке были конструкции для опциональной ленивости.   
В INRIA уже с лета 86-го стали использовать для написания доказателя. Версию CAML 2.5, используемую не позднее ноября 87-го, в INRIA считали более-менее стабильной [Huet15] и не позднее весны 88-го начали писать о ней в рассылках [Maun88]. Версию 2.6 в 90-ом предлагали [Neum90] выслать желающим за $300 ($740 в 2025).   
Этот CAML все еще не тот язык, который сегодня ассоциируется с этим названием. Но современный OCaml уже вполне узнаваем в нем, как и современный SML узнаваем в SML 85.9.   
Что в CAML узнать гораздо сложнее - это LCF/ML. Синтаксис комментариев и строк в CAML теперь как в SML. Больше нет соединений ключевых слов вроде `letrec` и `whererec`. Типы-произведения становятся `*` как в SML. Конструктор списка теперь `::` как в SML. Точки в лямбдах и `case`-выражениях заменили на стрелки, но одинарные `->`, а не двойные `=>` как в SML [Cous90].   
Да, незадолго до того в INRIA бережно добавили фичи HOPE в LCF/ML так, чтоб не потребовалось править каждую строку их кода на LCF/ML. И теперь там же спроектировали язык, который потребовал править практически каждую строку их кода на LCF/ML++, которого стало только больше. Мы не знаем, почему так произошло.   
CAML стал больше походить на SML в деталях, но остались отличия важные для представителей INRIA на заседаниях не-комитета. В CAML нет групп уравнений, обычных для HOPE-фицированных языков того времени, CAML - язык выражений, а не уравнений, в большей степени ISWIM, чем NPL. `let` остался как в LCF/ML, не похожим на тот, что в SML, и пока что никуда не делось выражение `where`.   
Есть различия, которые не обозначали как важные. Элементы в списках перечисляются через `;`, а туплы не плоские как в HOPE и SML, а состоят из пар.   
Основная причина несовместимости CAML с процессом стандартизации SML, по видимому, не желание сохранить побольше LCF/ML, как в случае с модифицированным Кузино Cambridge ML. CAML несовместим с SML-процессом из-за обилия новых фич. Они не ограничиваются опциональной ленивостью.   
В CAML множество экспериментов с паттерн-матчингом. Два вида лямбд. Одна лямбда - `function`, позволяющая многоветочный паттерн-матчинг, но не позволяющая упрощенной декларации каррированных функций. Как лямбда в HOPE, SML, одна из двух лямбд в OCaml и `\case` в Haskell.   
Но второй вид лямбд - `fun` - соответствовал не современным `fun`-лямбдам OCaml или `\`-лямбдам в Haskell, поддерживающим простую декларацию каррированной функции, но не многоветочный ПМ. `fun` в CAML поддерживает и то и другое, приблизительно как `\cases` в GHC 9.4.  

```ocaml
let chop_list = (fun n l -> chop_aux n ([],l))
  where rec chop_aux =
   fun 0 (l1,l2) -> rev l1,l2
     | n ->
         fun (_,[]) -> failwith "chop_list"
           | (l1,h::t) -> chop_aux (pred n) (h::l1,t);;
```

Но код на CAML развивается в сторону соглашения, соответствующего ролям `fun` и `function`, которые в OCaml устанавливаются самим языком.   
CAML большой и избыточный язык, в нем сосуществовали два синтаксиса для ПМ-выражений. И `case` `of` и более привычный программисту на OCaml `match` `with`. Но вторая конструкция использовалась чаще и к версии 3 осталось только выражение `match` `with`.    
Там появляются как более-менее знакомые нам сегодня или-паттерны, менее обычные версии обычных вещей, такие как `as`-паттерны в которых сложные паттерны могут быть с обеих сторон `as` одновременно, так и более необычные вещи, вроде парсеров, объявляемых как ПМ. Как этот ПМ-парсер, разбирающий код с ПМ [Caml261]:  

```ocaml
and Fnexpr =
    parse Literal "fun"; Match m -> MLmatch m
        | Literal "function"; Umatch um -> MLmatch um
        | Literal "match"; Expr e; Literal "with"; Umatch um
            -> MLapply (MLmatch um, e, [])
        | Literal "case"; Expr e; Literal "of"; Umatch um
            -> MLapply (MLmatch um, e,[]) ...
```

Важная причина того, что разработчики доказателей не спешили использовать VAX ML и SML, а продолжали выбирать Cambridge ML или собственную имплементацию ML - это средства метапрограммирования. В мета-языке для доказателя хотелось бы иметь средства для манипуляции кодом на языке для доказателя. И в CAML они есть.

```
let rec MAP f =
    function (<<[]>> as S) -> S
            | <<#x::#L>> -> <<(#f #x)::#(MAP f L)>>
```

Можно и конструировать AST с помощью цитат, и разбирать в ПМ.   
Но довольно привычные и ожидаемые теми, кто знаком с OCaml, гарды появились там не сразу, только в третьей версии в начале 90-х. Позже, чем в LML, но намного раньше, чем в SML.   
Наш обычный пример выглядит так:

```ocaml
type 't list = [] | prefix :: of 't * 't list;;

let rec map f = fun [] -> [] 
              | (h::l) -> f h::map f l;;

map (fun x -> x + y) [1; 2; 3] where y = 2
```

Его можно сделать еще более похожим на код на OCaml, но мы старались подчеркнуть различия.   

### Неравенство уравнений

Так в INRIA создали свою, узнаваемую разновидность HOPE-фицированных ML-ей. С паттерн-матчингом, но без групп уравнений. Это довольно привычно сегодня, но не в середине 80-х. Для большинства HOPE-фикаторов, добавление уравнений было чем-то самим собой разумеющимся. На каждый компилятор французского ML-я приходилось несколько имплементаций ФЯ с уравнениями. Несколько одних только имплементаций SML, которые в эти времена делали один за другим. И до того, как завершилось формальное описание его семантики, так что нельзя приписать успех решению эту семантику формально описывать.   

#### Edinburgh ML, SML/NJ, ML Kit

После того, как Карделли забросил свой компилятор, следующей главной экспериментальной имплементацией для SML не-комитетчиков стал его ранний форк Edinburgh ML. Разделение произошло, по видимому, задолго до начала переделывания компилятора Карделли из компилятора VAX ML в компилятор SML, так что наработки Карделли использованы не были. Тем более, что Митчелл с коллегами в Эдинбурге переписали Edinburgh ML с Паскаля на другой язык. В Edinburgh ML не заменили поддержку VAX ML на SML как сделал Карделли, а продолжили поддерживать VAX ML вместе с SML. Правда, VAX ML потерял статус ФЯ с нативным компилятором потому, что Edinburgh ML переделали из нативного компилятора в интерпретатор байт-кода. Справедливости ради нужно отметить, что переделали в интерпретатор нового поколения с заметно более высокой производительностью, чем у первой волны интерпретаторов ФЯ вроде LCF/ML, обеих основных SASL и Edinburgh HOPE. Почему из компилятора сделали интерпретатор? Об этом в следующей части.   
Эстафету главной песочницы SML-не-комитетчиков Edinburgh ML передал новому компилятору, который был компилятором SML с самого начала, написанному вернувшимся к имплементации ФЯ МакКвином и новым героем нашей истории Аппелем. Работа над этим новым компилятором Standard ML of New Jersey (SML/NJ) началась в Принстоне, в марте 86-го [MacQ14]. Осенью 87-го вышел первый доступный публично релиз.   
В 89-ом году в Эдинбурге Мадс Тофте и др. начали писать еще один экспериментальный компилятор ML Kit [MLKit2002].   
Все эти компиляторы сами являются важными экспериментами по написанию реальных программ на ML и будут подробно рассмотрены в следующей части.   
Но было еще несколько компиляторов SML, которые или стали экспериментами по написанию кода на ML не сразу. Или не стали уже никогда.   
Начнем с компилятора SML, написанного на самом нефункциональном языке - Паскале. Да, после стольких лет, нашлись еще имплементаторы ML кроме Карделли, готовые писать имплементацию ML на Паскале.   

#### ANU ML

Написанный на Pascal компилятор Карделли не пропал, после того, как Карделли забросил работу над ним. Один из первых авторов и имплементаторов LCF/ML Малкольм Ньюи, который после работы в Эдинбурге вернулся в Австралию работать в Австралийском национальном университете (Australian National University), создал там еще один форк компилятора Карделли, предпоследней его версии Pose 3. Этот компилятор, получивший название ANU ML [Berr90], был портирован на рабочие станции и даже на Макинтош. ANU ML имплементировал более новую версию SML и более полно, чем Pose 4. Но имплементация все же была не полной, не были имплементированы параметризованные модули и она отставала от самых последних представлений о том, как SML должен работать. Что не является нетипичным для имплементаций SML того времени.   
Интересно, что Ньюи, еще один "ядерный" разработчик LCF/ML, в отличие от своих французских и шведских коллег, похоже предпочел не LCF/ML, а что-то более HOPE-образное.   
SML-не-комитет узнал об ANU ML не позднее мая 88-го [Miln88], но он не перечисляется как доступная имплементация SML до 90-го года [Moss89] [Berr90]. К концу 80-х производительность генерируемого кода все еще оценивают как хорошую, а требования к памяти как более скромные, чем у новых компиляторов.   

#### Poly/ML

На заре HOPE-фикации Гордон и Полсон [Gord82] рассматривали Poly как перспективный источник идей для развития ML и даже как потенциальный язык для объединения в один с ML. Мэттьюз в дальнейшем писал, что неплохо было бы добавить в Poly паттерн-матчинг и конструкторы исключений с параметрами [Matt88], но ничего из этого не было сделано.   
Poly не был хопифицирован добавлением ПМ и АлгТД как VAX ML, Lazy ML, Cambridge ML. Компилятор Poly был использован как основа для компилятора SML. Но, поскольку Poly использовался для разработки самого компилятора (и, по видимому, ни для чего другого), возможность компилировать код на Poly осталась. Так же как поддержка VAX ML осталась в Edinburgh ML, имплементирующем SML.   
Первая экспериментальная версия Poly/ML была сделана до конца 83-го года [Matt89] и была пригодна для написания реальных проектов не позднее 86-го года. По мнению Полсона, Poly/ML был, на протяжении ряда лет единственной эффективной имплементацией SML. Что не удивительно, Полсон с самого начала не считал компилирующиеся через Лисп ML-и серьезными имплементациями по сравнению с Poly и VAX ML [Paul22b]. И в это время одна ветка VAX ML была заброшена, другая переделана в интерпретатор и третья пропадала на другом конце Земли и, по видимому, не была известна европейским и американским эмелистам до конца 80-х [Berr90].   
Дэвид Мэттьюз работал в Кембридже над Poly/ML один, по видимому, до конца 89-го года [Moss89]. Компилятор был портирован на популярные рабочие станции SUN 3, где требовал 3-6Мб памяти, но VAX-версия была заброшена [Berr90]. Распространяла компилятор компания Cambridge University Technical Services, занимающаяся коммерциализацией того, что делали академики в Кембридже. А именно, другие академики получали компилятор за 100 фунтов ($333 в 2025) [Wolf89], а коммерческий пользователь мог договориться во сколько ему обойдется лицензия. Но не позднее весны 1990-го CUTS передала права на разработку и распространение Poly/ML компании Abstract Hardware Limited, в которой Мэттьюз продолжил работу, но уже не один [Matt2000] [Berr90]. Abstract Hardware Ltd. продавала компилятор академикам за 500 фунтов ($1664 в 25-ом), а коммерческим пользователям за две тысячи фунтов ($6655 в 2025).   

#### POPLOG ML

POPLOG - система, разработчики которой старались сделать ее удобной основой для имплементации ФЯ. Разумеется ее использовали и для имплементации SML.   
С появлением популярных рабочих станций, POPLOG [Slom89] сделали более удобным для портирования на новые машины, для этого в нем теперь два промежуточных языка, с которыми работают имплементаторы расширений: PVM (Poplog Virtual Machine) - в это компилируют новые языки писатели фронтендов, PIM (Poplog Implementation Machine) - это имплементируют на новой машине писатели новых бэкендов. Весь конвейер между PVM и PIM машино- и языконезависим.   
С середины 84-го POPLOG работает на 4BSD, сначала на VAX, а позднее и на машинах с MC68K вроде рабочих станций SUN и Apollo, c 386 и менее важных.
Университет Сассекса продавал POPLOG с 82-го года [POP19], с существенными скидками для прочих академиков, с 83-го года продажами занялась компания Systems Designers Ltd. (позднее SD). В ней имплементацию MACLISP-диалекта Каннингема на основе POPLOG посчитали не соответствующей ожиданиям от коммерческого продукта и профинансировали новую, более серьезную имплементацию Common LISP. Деньги на это выделил и S(E)RC. Над имплементацией работал в основном Джон Уильямс (John Williams) под руководством Каннингема. Для этой имплементации как и для имплементации Пролога, в POPLOG добавили новые фичи. Гибсон внес изменения в виртуальную машину для лучшей поддержки статической видимости и исключений.   
В 86-ом году, в POPLOG версии 12, Common Lisp был уже имплементирован процентов на 90% [POPLOG], а в феврале 87-го состоялся релиз версии 1.0 Common Lisp фронтенда. К осени 88-го заработала даже оптимизация хвостовой рекурсии.   
Добавленная в POPLOG статическая видимость стала использоваться и в POP-11, сначала как опциональная, летом 86-го с версии 10.3 [POPLOG], а позднее и по-умолчанию. В последних версиях POPLOG пример Поплстоуна, демонстрирующий проблемы с возвращением функций больше проблемы не демонстрирует. Но превращение POP-11 в полноценный ФЯ Эдинбургской программы не состоялось, как и превращение Poly. Вместо этого Роберт Дункан (Robert Duncan) и Саймон Николс (Simon Nichols) написали на основе POPLOG имплементацию Standard ML, для которой улучшенная поддержка статической видимости как раз пригодилась.   
Версия 1.0 PML, как назывался Standard ML на основе POPLOG, появилась в октябре 88-го года, но не поставлялась в комплекте с POPLOG (в это время 13.6). Первоначальная имплементация SML доросла до версии 1.3 и в декабре 90-го сменилась версией 2.0, вошедшей в основной комплект поставки POPLOG 14 в 91-ом году.   
Считалось, что POPLOG SML генерировал код, который исполнялся немного помедленнее Poly/ML, но компилировал побыстрее [Appe91].   
В 90-ом году счастливым обладателем POPLOG можно было стать заплатив 7.5тыс. фунтов (25тыс. долларов в 2025-ом) [Berr90]. Для академиков скидка 85%!   

#### Rutherford ML

Standard ML получил поддержку от программы-наследника STI и Лаборатория Резерфорда - Эплтона подключилась к его разработке и имплементации. В 85-ом Вадсворт принял участие во встречах комитета, а в самой лаборатории занялись доведением Cambridge ML до полной и окончательной HOPE-фикации.   
Эта имплементация называлась Rutherford ML или Rutherford SML.   
Филип Микаэль Хедлунд (Philip Mikael Hedlund) начал работу в лаборатории в январе 85-го [Witt85]. К февралю 86-го Хедлунд под руководством Вадсворта [RAL87] написал новые парсер и проверку типов, которые сделали Rutherford ML компилятором подмножества Standard ML без модулей. Сделав это он приступил к улучшению генератора кода и рантайма [Duce86]. Заявляется, что оптимизации в новом генераторе кода на Лиспе улучшили время выполнения некоторых программ в 10 раз [RAL87], но нам не известно каких программ.   
Имплементация Rutherford SML была закончена в июне 1986. Тестировал новый компилятор SML Полсон в Кембридже [RAL87]. После этого Хедлунд начал работу над генератором парсеров для ML, но летом 87-го его работа в ЛРА закончилась и он вернулся в Швецию [Danc87].   
Cambridge LCF и, естественно, Cambridge ML и Rutherford SML в ЛРА заработали на IBM-совместимом мэйнфрейме с UNIX - Atlas 10 [Faul84] [Duce86]. Так в середине 80-х мечты Стрейчи и Уилкса осуществились уже полностью, Реально-Существующий-CPL (ML) заработал на пригодном для его использования Atlas (но 10, а не 1 и не 2 и разработанный Fujitsu).   
Машина с одним ЦПУ в 15 MIPS и, что более важно, с 16Мб памяти, так что нужно было меньше ждать когда страницы поднимут в память с диска. Так что Кембриджский Университет проверял на этой машине за минуты доказательства, которые требовали ночь работы VAX [GEC63] с процессором всего-то раз в 15 медленнее.   
И когда Кембридж использует очередной реальный CPL на очередном Atlas, то понятно, что другая организация мечтателей о CPL не остается в стороне. Королевский Радиолокационный Институт тоже захотел компилятор SML, но на этот раз не разрабатывал компилятор самостоятельно, а заказал [Berr90] его компании Harlequin Ltd. (Кембридж, СК), разработчику коммерческой имплементации Common Lisp.   
Но Cambridge ML с нестандартно HOPE-фицированным французским ML, даже заброшенный французами и с новоявленным стандартным форком-конкурентом не погиб и оставался, по видимому, более популярным, чем Rutherford ML, количество пользователей которого стало заметно падать уже через пару-тройку лет после первого релиза [RAL89].   
Жизнь Cambridge ML продлило и то, что в отличие от Rutherford ML, так и оставшегося компилятором ML через Franz LISP и прочие нестандартные и уже умирающие в эти годы Лиспы, Hewlett-Packard профинансировал [Gord2000] создание Кэрроллом (John Carroll) версии нестандартного Cambridge ML, компилирующего через стандартный Common Lisp.   

#### Да, fib

Давайте посмотрим, насколько быстро работает код, который генерируют компиляторы HOPE-фицированных ML-ей. Таблица показывает насколько больше вызовов функций делается за единицу времени по сравнению с интерпретатором LCF/ML.   

|                                       |   nfib   |
| :------------------------------------ | :------: |
| Le ML (CAML) [Maun86]                 |   197    |
| SML/NJ 0.18 [Augu89]                  |   115    |
| _C_ [Augu84]                          |   100    |
| ANU ML (VAX ML) [Augu84]              |   92.0   |
| Lazy ML [Augu89]                      |   59.0   |
| Cambridge ML V6.2 Franz Lisp [Maun86] |   31.5   |
| Poly/ML [Maun86]                      |   25.8   |
| Poplog ML [Berr90]                    |   25 ?   |
| Le LML [Maun86]                       |   16.0   |
| Edinburgh ML [Augu89]                 |   13.5   |
| _LCF/ML_ [Augu84]                     |   1.00   |

```
Le ML (CAML) [Maun86]
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
SML/NJ 0.18 [Augu89]
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
C [Augu89]
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
ANU ML (VAX ML) [Augu84]
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
Lazy ML [Augu89]
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
Cambridge ML V6.2 Franz Lisp [Maun86]
░░░░░░░░░░░░░░░░
Poly/ML [Maun86]
░░░░░░░░░░░░░
Poplog ML ? [Berr90]
░░░░░░░░░░░░░
Le LML [Maun86]
░░░░░░░░
Edinburgh ML [Augu89]
░░░░░░░
LCF/ML [Augu84]
░
```

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

### Пираты Кремниевой Долины

Академия стала переписывать свой Лисп-код с MacLisp-диалектов на Common Lisp. Видимо предполагая, что прочие Лиспы теперь не имеют будущего. В некоторых случаях так и вышло.   
InterLisp для имплементации ФЯ и до того не использовался, но Standard Lisp использовался, имел компилятор PSL, производящий быстрый код и получил поддержку HP. Для Standard Lisp разрабатывался новый экспериментальный компилятор EPIC [Kess86], компилирующий в семь стадий, больше похожий на оптимизирующие компиляторы S-1 Lisp и BLISS-11. Но Standard Lisp не поддерживал лексическую видимость и потому был не особенно удобен и эффективен для использования в качестве бэкенда компилятора ФЯ.   
Ожидалось, что этот недостаток будет преодолен, но преодолен одновременно с превращением в компилятор Common Lisp, что было еще одним поводом использовать CL, а не Standard Lisp.   
Сконвертировать наработки по имплементации хорошего компилятора Standard Lisp в хороший компилятор Common Lisp не удалось. Сделать хороший компилятор Common Lisp было вообще не легко, как это и было задумано, по крайней мере некоторыми, авторами его стандарта. Так что HP прекратил поддержку разработки PSL и Standard Lisp, заказав компилятор Common Lisp у коммерческой компании, основанной авторами стандарта [Stee96].   
Но не все нестандартные Лиспы прекратили существование, работы над Le Lisp продолжались.   
Торжество Common Lisp, тем временем, оборачивалось не самым удачным развитием событий для академии. Создание стандартного (со строчной буквы) Лиспа было использовано для того, чтоб перезапустить экосистему и превратить её из экосистемы насыщенной доступным для академии кодом, на основе которого можно строить что-то свое, в экосистему, в которой практически все работающее коммерциализировано и закрыто и академику не за что ухватиться.   
Эта новая коммерциализированная экосистема состояла из Лисп-машинистов, уступающих под натиском обычных рабочих станций, и использующих их остальных лисперов. Проблемы Лисп-машинистов мы изложили подробнее в прошлой части.   
Лисп-машинисты со временем придумали, как использовать победоносное шествие обычных рабочих станций. Не нужно пытаться продавать свои персональные мини-компьютеры величиной с холодильник, нужно продавать плату расширения - Лисп-акселератор, который лиспер будет вставлять в свои новые, все более мощные рабочие станции и даже простые ПК из верхнего ценового сегмента вроде Макинтоша. Эта идея несколько продлила жизнь Лисп-машинизма, но, по видимому, не стала достаточно релевантной для того, чтоб сыграть важную роль в нашей истории функционального программирования. Рабочие станции развивались быстро и акселератор для Лиспа был не так уж и нужен.   
Основными коммерческими имплементаторами Common LISP для рабочих станций были Lucid Inc. и Franz Inc. Некоторые производители обычного железа начали с разработки собственных имплементаций, но, со временем, отказывались от них в пользу продуктов Lucid, которая выступала OEM имплементатором для них. Franz больше работала с небольшими компаниями и индивидуальными программистами.   
Franz - это уже знакомые нам разработчики Franz LISP, самой популярной имплементации MACLISP-образного Лиспа, являющейся общественным достоянием. Для разработчиков ФЯ в академии это подходило, но группа Фейтмана в Беркли положила этому конец, став коммерческой компанией, которая сначала продавала новые версии Franz LISP, а с конца 86-го стала продавать ExCL (Extended Common Lisp), переименованный в 88-ом году в Allegro CL [Franz].   
Lucid основали важные разработчики Common LISP, которые написали компилятор с нуля в 85-ом. Компания привлекла 16 (49.5 в 2025) миллионов долларов венчурного финансирования [Gabr96]. Их соперники из Franz считают, что вместе с господдержкой набиралось 25 (77 в 2025) миллионов [Franz].   
Franz существовала на совсем другом уровне. Джон Фодераро тоже написал имплементацию Common LISP с нуля, но один, сидя дома за рабочей станцией, полученной от SUN или какого-то другого клиента из первых, как плата за портирование Franz LISP. Хотя Фодераро и писал код какое-то время один у себя дома, у него были коллеги. Офис располагался дома у другого со-основателя Фрица Кунце (Fritz Kunze), Фодераро просто не хотел "отвлекаться" на какое-то взаимодействие с ними.   
То, что Franz мог конкурировать с Lucid, по видимому, объясняется не какой-то необычной эффективностью Franz, а скорее необычной неэффективностью Lucid. И мы знаем, что они могли конкурировать потому, что даже SUN, отношения с которой считались ключевыми [Stee96] для выживания Lucid с 86 по 87-ой годы переключалась на сотрудничество с Franz.   
Сам CTO Lucid вспоминает [Gabr96], что программисты часто предпочитали Franz, но их руководство предпочитало Lucid. Например, основатели SUN из-за знакомства с основателями Lucid по университету.   
Он же считает, что Franz мог конкурировать с ними потому, что SUN предоставила тем альфы и беты ПО Lucid. Но это может быть проекцией. Потому, что он же вспоминает, как они сами пытались получить такой доступ к ПО Franz, но те пригрозили им судом.   
Их соперники из Franz называют причиной своей конкурентоспособности то, что из-за нищеты они разрабатывали свой софт на дешевых рабочих станциях, похожих на те, что использовали их клиенты [Stee96]. В Lucid писали на Лиспе сначала на Лисп-машинах Symbolics [Gabr96], а затем на топовых рабочих станциях SUN.   
Имплементаторы ФЯ в академии, которые стали переключаться с MACLISP-вариантов на Common LISP обычно делали свои проекты собираемыми как Lucid CL так и Allegro CL. Но этого было недостаточно. По понятным причинам важно, чтоб проект мог использовать и имплементацию с открытым кодом, может быть не такую качественную как коммерческая, но как-то работающую. И с этим дела обстояли не особенно хорошо.   

### Дети Дюны

Как мы выяснили в предыдущей главе, Spice Lisp стал эталонной имплементацией Common Lisp, код которой был общественным достоянием.  
Несколько имплементаторов коммерческих Лиспов воспользовались этим. В DEC использовали код Spice Lisp для имплементации Лиспа на своих машинах вроде VAX. В TI - для MC68K [Stee96]. Самые важные платформы для имплементации ФЯ в это время. Но ни эти разработчики, ни прочие, из тех что использовали Spice Lisp не отдали никакого кода в Spice Lisp. Ни VAX, ни MC68K бэкенда он не получил.   
Сегодня коммерческие разработчики развивают проекты вроде LLVM даже если их не обязывает лицензия. Но у Столлмана были все основания ожидать, что без такого принуждения не обойтись. Коммерциализаторы Лиспа в 80-е это убедительно продемонстрировали.   
Тем временем, в 1985-ом году финансирование проекта SPICE прекратилось [MacL15], проект закрылся.   
Но разработка бывшего SPICE LISP продолжилась, только теперь он назывался CMU Common Lisp (CMUCL) и был небольшой автономной [CMUCL] частью нового проекта университета Карнеги-Меллона. Этот проект был представителем успешного направления по созданию параллельных машин с разделяемой памятью, которое привело к созданию обычных современных компьютеров. А именно проект по написанию ядра ОС для таких машин, совместимого с 4BSD - Mach (так Джуизе записал произнесенный Рашидом придуманный Тевоняном акроним MUCK, Multiprocessor Universal Communication Kernel).   
Нужно отметить, что роль имплементации Лиспа на Mach была существенно менее важной, чем имплементация Лиспа на 3BSD в Беркли несколькими годами ранее, о которой мы писали в нулевой части нашей истории. 3BSD для VAX создавался практически для того, чтоб использовать Franz LISP и написанные на нем программы. Позднее, 4BSD для MC68K уже не был так связан с Лиспом, и получил Franz LISP с некоторым опозданием. Но это не идет ни в какое сравнение с тем, насколько неважным был CMUCL для проекта Mach. Разработчики Mach заявляли поддержку Common Lisp [Acce86], но ни на популярных и важных для истории ФП VAX и MC68K ни на остальных, поддерживаемых Mach платформах, CMUCL в 80-е так и не появился [Rash89] [McDo89]. Кроме одной.   
Нашлась одна коммерческая компания, которая не просто взяла общественное достояние - код SPICE LISP/CMUCL - и использовала для своих нужд, ничего не вернув в CMUCL, но решила поучаствовать именно в развитии его кода и сделать свою платформу первым обычным компьютером на котором он будет работать. И так получилось, что единственной на все оставшиеся 80-е. Этой компанией была IBM.   
Платформа была не той, о которой вы, скорее всего, подумали. В IBM решили выйти на рынок рабочих станций со своей новой платформой RT, поконкурировать с SUN и Apollo.   
Но лисперы нашли ответ на эту новую угрозу появления открытой имплементации Лиспа. Руководитель группы разработчиков SPICE LISP/CMUCL Фалман был одновременно и основателем Lucid. И он воспользовался своим положением руководителя группы для того, чтоб убедить IBM заказать разработку имплементации Лиспа для их новой рабочей станции у Lucid. И ему это удалось. Но дальше события развивались не очень благоприятно для Lucid, и хитрый план Фалмана был источником многих проблем, большинство из которых не выглядит такими уж неожиданными.   
Для начала, этичность и даже законность действий Фалмана показалась IBM сомнительной. Возникли опасения, что кто-то из переигранных Фалманом может обратиться в суд. В IBM решили обстоятельно изучить такие риски и потратили на это от полугода до года. Только после этого IBM заключил договор с Lucid.   
Это не только задержало деньги от IBM. Фалману удалось уговорить IBM давать эти деньги ему, а не университету Карнеги-Меллона в числе прочего и потому, что дедлайн не изменился. И до него теперь оставался только один год.   
Тут дала о себе знать следующая проблема. У Lucid уже был собственный компилятор, но не было инструментов вроде редактора, отладчика и библиотек, например для графического интерфейса пользователя. К счастью, все это было написано в УКМ в рамках проекта SPICE и Lucid просто взяла написанный в университете код в надежде доработать его до индустриального уровня. Но написанный в университете код оказался не таким уж хорошим, а требования IBM к индустриальному уровню повыше, чем ожидали лисперы.   
Наконец, IBM почему-то не понравилось, что Lucid хочет продать им как документацию написанные на деньги DARPA руководство пользователя и репорт по Common LISP. Представьте себе, пришлось в Lucid еще и документацию писать. Которая была, в основном, копией репорта. Гэбриел называет её "редакцией Пьера Менара" и тратит на объяснение шутки страницу своей книги, сопровождая пояснение обширной цитатой из Борхеса.   
Короче говоря, как и в случае с лисп-машинами, с приватизацией прибылей поторопились, еще не все убытки были национализированы.   
Проблема, которая оказалась неожиданной (для 80-х годов) заключалась в том, что новая рабочая станция IBM провалилась.   
Вся эта история нанесла Lucid значительный ущерб, пишет Гэбриел, "возможно, что невосполнимый".   
Как видно, у лисперов не было недостатка решимости ударить других лисперов ножом в спину. Но, обычно, недоставало способности сконвертировать этот удар в свою победу или выгоду для себя.   
Забавно, что эта история описана не какими-то злопыхателями из Franz, а одним из основателей Lucid Гэбриелем [Gabr96], который неиронично считает себя, Фалмана и других своих коллег по Lucid жертвами IBM.   
Что успели сделать для IBM RT в университете Карнеги-Меллона [MacL15] - это рантайм в шесть тысяч строк ассемблера и раскрытие команд SPICE-Lisp байт-кода в стиле компиляторов Уоррена и Карделли. Что наверное было не очень хорошо для байт-кода, который планировалось интерпретировать микрокодовым интерпретатором на PERQ. Но насколько это было плохо было бы важно в том случае, если б IBM RT была хоть сколько-нибудь популярна, а она не была.   
В 85-ом году один из разработчиков CMU CL (из тех, у кого не было собственной Лисп-компании) Маклахлан (Rob MacLachlan) начал работу над более серьезным компилятором для этой имплементации Лиспа под названием Python [MacL15]. Компилятор для Лисп-системы часто носит отдельное название. Так компилятор Franz Lisp назывался liszt, а компилятор Le Lisp назывался Complice.   
Но до конца 80-х компилятор CMUCL Python не генерировал код ни для каких релевантных для нашей истории платформ. В 90-е генерировал, но это уже другая история.   

### Отец с атомным сердцем

Как видно, в это время в США было не много лисперов, желающих разрабатывать имплементации Common Lisp с открытыми исходниками. Возможно, что это объясняет, почему последнюю версию Franz Lisp, являющуюся общественным достоянием не попытались превратить в компилятор Common LISP, например, использовав CMU CL как фронтэнд.   
Помощь пришла из Исследовательского Института Математических Наук Киотского Университета (Research Institute for Mathematical Sciences, Kyoto University).   
Юаса Тайити (Yuasa Taiichi) и Хагия Масами (Hagiya Masami) написали имплементацию [Yuas85] Common Lisp под названием Kyoto Common Lisp без особого взаимодействия со своими американскими коллегами, просто по описанию Стила [Stee84]. На 60% на C и на 40% на Лиспе. Это было не ново, Franz Lisp тоже имел портируемый рантайм на C. Новым было то, что компилятор KCL транслировал Common Lisp в C-код для последующей компиляции компилятором C. Европейские и американские имплементаторы Лиспов и ФЯ считали такой подход бесперспективным [Stee96]. И появление этого компилятора изменило их мнение, в конце 80-х и начале 90-х многие попробовали этот подход. Но это уже другая история.   
Компилирование через C означало медленную компиляцию и легкость портирования. Лисперы вспоминают, что и конкурирующие с KCL компиляторы тоже не отличались высокой скоростью компиляции. А вот легкость портирования была важной.   
Первой машиной, для которой написали KCL был миникомпьютер Data General Eclipse MV, но не позднее ноября 85-го появились версии для более актуальных миникомпьютеров VAX-11 и рабочих станций SUN с BSD 4.2.   
Портирование KCL на первую Unix-машину заняло три дня до первой работающей версии и еще несколько дней на устранение ошибок. Портирование на следую Unix-машину было сделано уже "за три вечера".   
Как компилирование через C сказалось на производительности? К этому мы еще вернемся.   
Конечно же, последняя версия KCL вышла уже в июне 87-го. И эту имплементацию коммерциализировали как Ibuki Common Lisp. Но, как и в случае с компиляцией через C, произошло некоторое отклонение от американской лисперской нормы. Киотский университет продолжал раздавать последнюю версию бесплатно всем академикам, которые напишут им обычное, не электронное письмо [Boye92]. Так что академик мог продолжать выпускать патчи для этого последнего KCL но не мог потом основать собственную фирму, которая будет продавать этот код, как уже поступили многие коллеги с кодом-общественным достоянием.   
Теоретически, развивать KCL таким способом мог любой желающий академик, но на практике нашелся только один, по крайней мере в 80-е.   
В прошлой части мы писали, как МТИ сделал из MACSYMA-общественного достояния MACSYMA-коммерческий продукт, который должен обеспечить преимущества для Лисп-машинистов из Symbolics. И что департаменту (министерству) энергетики США не особенно понравилось, что их многолетние вложения стали чьим-то там коммерческим продуктом. И МТИ передал им код MACSYMA на мертворожденном Лиспе NIL с некоторыми ограничениями для распространения. Для начала, эту DoE MACSYMA нужно было переписать на язык поживее и энергетики нашли для этого подходящего человека [Fate2003].   
Уильям Шелтер (William Frederick Schelter) с 79-го года работал в Университете Остина вместе с нашим старым знакомым по нулевой части Бойером. Шелтер поддерживал код DoE MACSYMA с 82-го года и со временем переписал его на Common Lisp. Ожидалось что этот Лисп будет поживее NIL, в академии стали писать на нем, вот и очередная версия доказателя Бойера-Мура на нем, и очередная производная LCF с Cambridge ML, будут на нем писать и другие программы о которых мы еще планируем рассказать подробнее в другой раз.   
И когда KCL перестал обновляться, пришлось Шелтеру разрабатывать набор патчей для него - Austin Kyoto Common Lisp. Пока CMUCL не начал поддерживать хоть какие-то актуальные для академии платформы, вся экосистема открытого кода на Common Lisp держалась на одном человеке.   
Так что технически компиляция ФЯ через Common Lisp была возможна, но возможность эта была пока что не особенно привлекательна. Так что имплементаторы ФЯ желающие использовать Лисп рассматривали и другие варианты. Но это уже другая история.   

Big in Japan
------------

> Срочный, захватывающий и грамотный репортаж о головокружительном будущем компьютерной революции.   
> San Francisco Chronicle   

> Это не просто вторая компьютерная революция, это важнейшая из двух.   
> Эдвард Фейгенбаум [Feig83]   

> УЛЕТ, ОТПАД!   
> The New York Times   

> Настоятельно рекомендуем... должно быть прочитано каждым, кого интересует экономическое и технологическое будущее.   
> Library Journal   

В прошлой части мы оставили создателей (симуляторов) специализированного железа в не самое лучшее для них время. Но перед тем, как дела у них пошли совсем уж плохо, ситуация ненадолго улучшились. Помощь пришла из Японии.   
Еще в 79-ом году в Министерстве международной торговли и промышленности Японии (Ministry of International Trade and Industry) появилось желание начать амбициозный проект по созданию компьютера нового поколения [Shap83]. Следующее поколение выходило пятым, так этот проект впоследствии и стали называть. По видимому, это была реакция на обсуждения "кризиса программного обеспечения" и стартовавшие в 77-79-ом проекты, о которых мы уже рассказывали.   
Министерство выяснило, что считает компьютером будущего индустрия. Оказалось, что в индустрии считают, что это графическая рабочая станция с большой памятью для микрокода вроде тех, что сделали в лабораториях Xerox. И сеть будущего - это Ethernet.   
Тут они были правы, в 80-е многие делали рабочие станции и даже персональные компьютеры верхнего ценового диапазона вроде Макинтоша, на которые явно повлияли эти машины. Микрокодовый аспект, правда, не был важным. Но этот ответ не понравился министерству.   
И дело не в том, что для успеха нужно пробовать что-то новое, а не пытаться сделать лучше то, что уже кто-то делает. Предыдущие программы министерства как раз направляли такое догоняющее развитие и были успешны. Может быть, слишком успешны. Потому, что сформировали стереотип, который министерство хотело сломать новой программой.   
Для того чтоб продолжать заниматься тем, чем все компьютерные компании занимались и так, помощь министерства промышленности уже не требовалась. Весь смысл был в том, чтоб попробовать по-развивать что-то, что компьютерным компаниям обычно не так интересно. Но что именно? Как мы выяснили в предыдущих главах, придумано уже довольно много вещей, которые компьютерным компаниям не так уж интересны.   
И работник NTT Мураками Кунио (Kunio Murakami) нашел для министерства промышленности обладателей виденья достаточно амбициозного будущего: это были знакомые его начальника Мото-Ока Тору (Moto-Oka Tohru) и Фути Кадзухиро (Fuchi Kazuhiro). Познакомились они за десятилетия до того в университете в США. И достаточно интересным виденьем будущего, которое они нашли для министерства промышленности, были параллельные компьютеры программируемые на Прологе. У японской промышленность не было никакого энтузиазма, там точно не стали бы заниматься этим, если б не министерство промышленности. У неяпонской промышленности энтузиазма тоже не было. То что надо!   
Почему параллельные машины программируются именно на Прологе? Фути интересовался МТИ-антипрологом Planner и идеями Ковальского но не считал их особенно практичными. Но в 76-ом году Фурукава Коити (Furukawa Koichi) привез Фути из SRI ксерокопию ксерокопии ксерокопии распечатки FORTRAN-исходников Марсельского интерпретатора Пролога. Восстановленный Фути по распечаткам Марсельский интерпретатор работал быстрее, чем он ожидал и его мнение о практичности идей Ковальского изменилось в лучшую сторону. Мото-Ока решил, что Пролог - язык будущего не только потому, что был знаком с Фути, но и потому, что Пролог полюбили его студенты.   
Помогло победить Прологу еще и то, что он соревновался не с такими же и даже более экзотическими языками, о которых мы писали в предыдущих главах, а с Лиспом. И Лисп в это время выглядел еще слишком нормальным для министерства промышленности, еще не откололся от унылого мейнстримного будущего рабочих станций.   
Планы был обнародованы в октябре 81, а проект стартовал в апреле 82-го года. Для осуществления плана был сформирован исследовательский институт ICOT, Фути стал его директором, Мураками - руководителем лаборатории, занимающейся железом, а Фурукава - руководителем лаборатории, занимающейся ПО.   
Бюджет на 83-ий финансовый год был 11 миллионов долларов ($36.8M в 2025) - полтора проекта MAC 63-его года. За десятилетие получилось 320 миллионов долларов (миллиард долларов 2025-го).   
Насколько это много? Сотрудник министерства международной торговли и промышленности Накамура посчитал, что не особенно много [Odag97], он утверждает, что каждый год, пока проект продолжался, он никогда не превышал 1% от расходов на R&D японской коммерческой электроники и телекома. И в один только первый год японского проекта по созданию компьютера пятого поколения в IBM потратили на R&D в пять раз больше, чем японцы на весь проект компьютера пятого поколения.   
Можно согласиться, что это мало для создания компьютера пятого поколения. Но похоже на то, что это существенная поддержка для Пролога. Разумеется, только часть этих средств были потрачены на важные для развития Пролога работы. Но это означает, что в течении десятилетия только в ICOT в лаборатории Фурукавы над программным инструментарием для Пролога постоянно работали 8-10 человек. Что по-видимому сравнимо с вкладом Mozilla в развитие Rust. Конечно, начало такого десятилетия для Пролога было во времена, когда программисты писали по тысяче строк в год, так что сравнимые ресурсы вряд ли давали сравнимый результат.   
Но даже скромные результаты были нужны для Пролога, который к началу японской инициативы переживал не самые лучшие времена. В это время компилятор Уоррена гибнет вместе с PDP-10. И чтоб начать что-то писать на Прологе в ICOT приходится использовать доживающие последние годы машины DEC, на которых работает единственная серьезная имплементация Пролога.   
Но мы не пишем историю Пролога. И для нашей истории важнее не японский проект по созданию "компьютера пятого поколения", а реакция на него. А реакция была существенной.   
Дело в том, что в 80-е, после успехов предыдущих и до потерянных следующих десятилетий, к тому, что считают перспективным в Японии относились серьезно. Первые сообщения о японском проекте не были сфокусированы на Прологе и новости о том, что в Японии считают ИИ перспективным были использованы для того, чтоб вдохнуть новую жизнь во многие проекты. Или правильнее сказать - гальванизировать многие проекты.   
Дело не ограничивалось Прологом или параллелизмом. Например, Эдвард "Отец экспертных систем" Фейгенбаум (Edward Feigenbaum) и Памела МакКордак (Pamela McCorduck) написали книгу под названием "Пятое поколение: искусственный интеллект и японский компьютерный вызов миру" [Feig83]. Книга вышла в 83-ем, а в 84-ом её переиздали в мягкой обложке, на которой изображена Статуя Свободы в гриме осирои, держащая факел в механической руке. Фейгенбаум "раздувал" японскую угрозу, считает пишущая историю ИИ-стартапов 80-х Филлипс, чтобы напугать своего читателя и подтолкнуть его к действию. Успешно. Что же читатель должен был делать? Разумеется, платить отцу экспертных систем деньги.   
Он поучаствовал в основании двух компаний [Phil99]. Первая - называвшаяся сначала IntelliGenetics, а позднее IntelliCorp, пыталась коммерциализировать экспертную систему MYCIN, над которой  Фейгенбаум работал в 70-е годы в Стенфорде. Не данные, но саму программу на Лиспе, которую предполагалось наполнять данными пользователя. Этой компании противостояла вторая компания, основанная Фейгенбаумом - Teknowledge. Вторая компания должна была победить первую, продавая более дешевый инструментарий для создания экспертных систем, работающий на более дешевых компьютерах. Как этого можно было добиться? Использовав вместо Лиспа и Пролога новый, перспективный язык для разработки искусственного интеллекта - C. Teknowledge была открывателем и законодателем моды на этот язык среди разработчиков экспертных систем 80-х. Да, успехи по избавлению от ассоциации с ИИ у разных языков и "парадигм" программирования были очень разными.   
К этой очередной победе лисперов над Лиспом и ее последствиям мы вернемся позднее, а сейчас настала очередь важнейшего для нашей истории ответа на японский вызов. И важнейшим для нашей истории был ответ британцев, которые уже 

### Успели забыть о Прологе больше, чем японцы успели узнать

Великобритания ответила на японскую программу пятого поколения в июне 83-го программой Алви (Alvey). Джон Алви (John Alvey) - это председатель комитета, который рекомендовал ответить. Ответ был размером в 350 миллионов фунтов (1 миллиард 830 миллионов долларов в 2025). Из них 200 были от государства и 150 от коммерческих компаний [Blac85] [Oakl90].   
Да, это почти в два раза больше средств, потраченных за примерно вдвое меньшее время. Потраченных экономикой меньшего размера, чем японская. И не смотря на все это, история с пятым поколением ассоциируется в основном с Японией.   
Ответ не предполагал создания специального института, хотя наш знакомый по нулевой части Мики и пытался это организовать.   
Как обычно, новости из Японии были представлены всеми как убедительное подтверждение того, что им нужно и дальше продолжать делать то, что они и так делали. Правда, новостей о том, что искусственный интеллект объявили чем-то перспективным в Японии, по-видимому, было еще недостаточно для реабилитации его в Британии после отчета Лайтхилла, так что ИИ обычно фигурирует под псевдонимом "интеллектуальные базы знаний", IKBS (Intelligent Knowledge-Based Systems).   
Кому из героев нашей истории лучше всего удалось убедить, что им нужно продолжать давать деньги на то же самое? Это были создатели (симулятора) HOPE-машины ALICE из Имперского Колледжа Лондона, группа Дарлингтона.   
В рамках программы Алви разрабатывались четыре проекта, "большие демонстраторы". И компании -  основные исполнители двух из них посчитали (или, может быть отдельные элементы внутри этих компаний посчитали), что им понадобится параллельный компьютер вроде ALICE.  
ICL занималась системой для министерства здравоохранения, а Plessey - самым амбициозным проектом программы Алви: распознаванием речи.   
ICL (International Computers Limited) - компания, разрабатывавшая компьютеры на которых использовали POP-2 в Эдинбурге и KRC в Кенте. ICL в 60-е купила компьютерный отдел Ferranti, которая в свое время построила Atlas и Atlas 2, для которых пытались имплементировать CPL. И вот эта компания ICL решила построить для Дарлингтона с коллегами ALICE, которую те только симулировали. И похожий на ALICE, но новый параллельный компьютер, который разрабатывали уже для программы Алви.   
И благодаря предполагаемой нужности для двух демонстраторов из четырех, проект создания этого компьютера стал самым большим проектом программы Алви. 3 декабря 85-го британский министр промышленности и информационных технологий обнародовал детали [Dett86]. И раз уж проект самый большой - его называли Flagship. Насколько большой? 15.5 миллионов фунтов (80 миллионов долларов в 2025). Новый проект объединял проект ALICE Имперского колледжа Лондона с проектом Университета Манчестера, построившего dataflow-машину MDF.  
ICL построила три прототипа ALICE. Первый прототип ALICE заработал в феврале 86-го [SPJ87] [Fiel88]. Так ALICE стала реальностью, но реальность эта оказалась не слишком радужной. Реальная машина работала "разочаровывающе медленно" [Clac24].   
Насколько медленно? nfib-число этой машины было 16000 [Harr87], что немного побыстрее, чем SKIM II, но в два раза медленнее, чем NORMA. И это производительность всей параллельной машины. Один переписыватель графов в ней, более точный аналог SKIM II и NORMA имел nfib-число в 1000.   
У разочаровывающе медленной работы было несколько причин. Реальная ALICE, которую построили в ICL, существенно отличалась от ALICE, которую задумывали в Имперском Колледже. Предполагалось [Dett86], что сеть, соединяющая вычислительные элементы с памятью будет работать со скоростью 300Мбит/сек., реальный кастомный чип, который переключал соединения между вычислительными элементами мог переключать достаточно быстро, чтоб обеспечить скорость в 150Мбит/сек., а реальные вычислительные элементы, построенные на Transputer, британской компании INMOS могли установить соединение только в 10Мбит/сек. Но такой медленной сети хватало, чтоб продемонстрировать хорошую распараллеливаемость вычисления чисел Фибоначчи потому, что переписыватели графов были очень медленными - интерпретаторами промежуточного языка ALICE ISL (Implementation Specific Language), написанными на OCCAM [Harr87].   
Эти проблемы можно было исправить, в 86-ом году уже умеют делать переписыватели графов намного быстрее. Но главная проблема ALICE не имела отношения к особенностям имплементации в ICL, она была архитектурной. Даже задуманная сеть в 300 Мбит/c не лучшее средство для соединения вычислительных элементов имеющих только 64Кб локальной памяти с блоками памяти в 2Мб, как это предполагали делать разработчики ALICE.   
У новой машины Flagship, которую разрабатывали в университете Манчестера и собирались построить в ICL к 88-му году, другая архитектура. В Flagship нет разделения на блоки памяти и вычислительные. У каждого вычислительного блока мегабайты памяти, к которой он имеет более быстрый доступ, чем через сеть к памяти остальных вычислительных блоков. И эксперименты с симулятором показали, что можно добиться 90% обращений к памяти в том же вычислительном блоке вообще без создания нагрузки на сеть для соединения блоков. И вычислительные блоки делались на процессорах MC68020. Пусть не британских, зато быстро работающих.   
Но для нашей истории, конечно, важнее не эти машины, а что машинистами было сделано полезного для имплементаций на обычном железе.   

### Новая надежда

Flagship был частью британского ответа на планы японцев по построению Пролог-машин. Но главным языком программирования этого проекта стал не Пролог, а HOPE.   
Не единственным. Работали над имплементациями на Flagship-машине и других языков, в том числе и Пролога. Но главным - на котором должно был быть написано системное ПО - выбрали HOPE.   
Причиной того, что выбрали HOPE, а не Пролог называют [Kean94] то, что в Имперском Колледже Лондона группа Дарлингтона уже занималась имплементацией HOPE и просто продолжила делать то, что уже делала. Что было вполне обычной реакцией на японский проект. Но Имперский Колледж был и важным центром по работе над Прологом. Ковальский из Эдинбурга отправился работать как раз туда.   
Трудно сказать насколько на выбор языка повлияли технические аргументы, а не какие-то административные маневры, но аргументы были.
Во-первых, Пролог из за красных катов и императивных "предикатов" - менее "декларативный" язык, чем чисто функциональный ФЯ. Программисту на Прологе поэтому нужно больше думать о процедурной семантике.   
Проблема этого аргумента в том, что те же претензии можно предъявить и к реально существующим в это время функциональным языкам. Как мы помним, эдинбургский HOPE только называется чисто функциональным, в реальном коде используют функции с побочными эффектами, написанными на POP-2. Как решать практические проблемы вроде ввода-вывода не нарушая чистоту языка пока не придумали.   
К истории того как эти проблемы решали в ФЯ и некоторых логических языках мы вернемся в следующей части.   
Следующим преимуществом ФЯ называют то, что ФЯ с хорошей производительностью имплементировать легче, чем Пролог. Что звучит правдоподобно, но как мы выяснили в нулевой части нашей истории, имплементацию Пролога с хорошей производительностью удалось сделать раньше, чем такую имплементацию языка, похожего на HOPE.   
С остальными аргументами поспорить значительно труднее: в HOPE есть типы и функции высшего порядка, а в Прологе их нет.   
Уоррен, правда, убеждал, что конструкции высшего порядка в Прологе и не нужны. Но убеждал не очень успешно в описываемое время. Сегодня мы знаем, что он победил и Пролог остался Прологом. Но в 80-е появились планы по усовершенствованию Пролога примерно таким же образом, каким в это время усовершенствовали ФЯ.   
Когда-то типов и ФВП не было и в NPL и Пролого-образные языки позднее расширят и типами и ФВП. Но, по видимому, слишком поздно. О HOPE-фикации Пролога мы расскажем подробнее в другой главе.   
Роль основного языка принесла и новые вызовы. Эдинбургский HOPE, E-HOPE, как его называли в Лондоне - ФЯ не самый практичный. И его эдинбургский интерпретатор - тем более.   
И решение этой проблемы нельзя откладывать до появления HOPE-машины. Нужна быстрая имплементация для обычных машин. Потому, что нужно писать код еще до того, как первый прототип специальной машины будет готов.   
На судьбоносном совещании в лаборатории Резерфорда - Эплтона Лондонская группа сообщала, что собирается написать более быстрый интерпретатор промежуточного языка, чем симулятор параллельного компьютера.   
И можно бы было ожидать, что более практическая имплементация HOPE для обычных машин будет просто еще одним бэкендом для компилятора в инструкции параллельной машины. Который транслирует из того же промежуточного языка. Со временем такой компилятор действительно появился. Но только со временем.   
Сначала в Лондоне написали один за другим два компилятора HOPE для разработки на обычных машинах, которые имели мало общего с компиляторами для параллельных машин. В самом большом проекте британской программы по созданию компьютера пятого поколения такое могли себе позволить. Развитие событий практически неизбежное потому, что этот самый промежуточный язык для новой специальной машины разрабатывался не в Лондоне и даже не в рамках того же проекта. Даже сегодня разработчики могли бы выбрать что-то внутреннее, не отягощенное координацией с другим проектом. Что уж говорить о временах бумажной корреспонденции и посылок с магнитной лентой.   
Нежелание использовать результаты этого параллельного проекта оправдалось, промежуточный язык не был готов к тому времени, когда Лондонской группе Дарлингтона уже нужно было начинать писать ПО на HOPE.       
Первый компилятор - IC HOPE для VAX-11 написал Энтони Филд (Antony Field) [Fiel88] [Perr91], имплементировав виртуальную машину под названием FPM (Functional Programming Machine). Есть ссылки на недошедший до нас университетский отчет 85-го года о нем.   
Имплементаторы HOPE противопоставляют FPM остальным функциональным виртуальным машинам и утверждают [Perr91], что с имплементациями обычных языков программирования вроде Algol 60 у FPM больше общего. Спорное утверждение. Может и справедливо в случае G-машины или CAM, но FPM довольно похожа на FAM Карделли или имплементацию Poly (ML).   
FPM - это очередная практичная версия SECD с поддержкой замыканий и оптимизация хвостовых вызовов. С копирующим сборщиком с фиксированным размером кучи. Там типы данных - обычно объекты кучи с тегами, но есть пары без поля для тега. И целые числа не являются объектами в куче вовсе, отличаются от указателей с помощью двухбитных тегов. Все это гораздо ближе к FAM, чем даже к самым смелым мечтам о функциональном Алголе 68, что уж говорить об Алголе 60.   
Существенное отличие от FAM только в том, что в FPM отсутствуют оптимизации для каррирования. Это  объяснимо, объявления функций в HOPE (пока что) не декларируют каррированные по умолчанию функции.   
И IC-HOPE похож на компилятор Карделли. Операции ВМ разворачиваются макросами. И производительность генерируемого кода вычисления чисел Фибоначчи получилась побыстрее LML, но помедленнее, чем SML/NJ. Как и у компилятора Карделли.   
Хорошо измерить производительность, правда, не успели. Первый компилятор быстро устарел, потеряв актуальность вместе с VAX-11. На смену этому компилятору для VAX вскоре пришел следующий компилятор, для MC68K.   
Этот компилятор написали [Perr91] Найджел Перри (Nigel Perry) и Кейт Сефтон (Keith Sephton). Рантайм был доработан и куча теперь могла расти во время исполнения. Генерируемый код стал заметно быстрее.   
Имперский Колледж Лондона распространял этот компилятор, анонс появился в рассылках в декабре 88-го года.   
Переход на более перспективную платформу - не единственная причина для развития компилятора. Проблему практичности Эдинбургского HOPE не решить одной только быстрой имплементацией. Нужны изменения в самом языке.  
Интересно, что с развитием HOPE сложилась ситуация, симметричная ситуации с развитием ML. Ядро разработчиков HOPE в Эдинбурге не особенно заботилось о похожести в деталях и забросило HOPE, начав проектирование Standard NPL. Извините, Standard ML. Периферийная группа разработчиков в Лондоне заботилась о сохранении детального сходства с HOPE гораздо сильнее, как и в случае с ML и INRIA.  
Но в случае HOPE это более объяснимо, чем в случае ML. Эдинбургские разработчики NPL, HOPE и SML никогда особенно не заботились о деталях. И каждая версия, которых было множество, требовала бы править практически каждую строку кода. Если бы он был. Это кардинально отличается от LCF/ML, который не менялся долгие годы.   
И стремление группы Дарлингтона изменять HOPE меньше не было полностью добровольным. У того, что HOPE стал основным языком флагманского проекта директората Алви, были не только полезные для его практичности последствия. Оказалось, что раз уж на заседаниях комитетов и комиссий договорились имплементировать HOPE, то нужно имплементировать HOPE а не какой-нибудь SML. Не совсем понятно какие отклонения от HOPE группа Дарлингтона могла себе позволить, но какие-то могла. Если и не HOPE 2, то по крайней мере HOPE+.
 И второй компилятор имплементировал этот HOPE+.   
Некоторые изменения в HOPE+ по сравнению с HOPE были сделаны для решения тех же проблем и решения были теми же, что в SML. В HOPE+, как и в SML, добавили [Darl89] [Robe89] целые числа со знаком и числа с плавающей точкой, массивы и стандартные 8-битные символы.   
Судя по "категорному" коду, про который мы рассказывали в нулевой части, немногочисленные программисты на HOPE любили писать много локальных функций не требующих сигнатур с указанием типов. В отличие от тех, что на топлевеле. Так что в HOPE+ написание таких функций сделали удобнее, разрешив в `let` и `where` рекурсию.   
Некоторые решения, хоть и были похожими - все же отличались. В HOPE планировали добавить исключения и их добавили и в SML и в HOPE+, но это были разные разновидности исключений. Чтоб не нарушить чистоту языка в HOPE+ сделали значения-ошибки, населяющие каждый ссылочный тип.   
В новом HOPE (пока) не сделали функции каррированными по умолчанию, но в функциональном языке удобное частичное применение желательно, так что оно все равно было добавлено. Добавлено, как и в SML, но не такое как в SML. В новом HOPE можно было писать `f(?,x,?)` что соответствовало такой вот лямбде `lambda (a, b) => f(a, x, b)`.   
Но некоторые выводы, которые сделали из опыта применения HOPE в Эдинбурге существенно отличались от выводов сделанных в Лондоне.   
Опыт имплементации перегрузки в HOPE не считался особенно удачным, в основном из-за сложного и медленного алгоритма. В Эдинбурге не отказались от перегрузки полностью, как в свое время в LCF/ML. Но в SML она осталась для ограниченного набора операций. В новом HOPE перегрузка для пользовательских функций осталась, но имплементированная с помощью более быстрого алгоритма и несколько иначе. Старое поведение перегрузки не было определено ничем кроме эдинбургской POP-2 имплементации и не было воспроизведено полностью.   
В SML отказались от паттерн-матчинга независящего от последовательности уравнений, который считали важным разработчики языков алгебраической спецификации. В Лондоне не порвали с этим алгебраическим прошлым и последовательность уравнений не стала важной как стала важной в SML, Прологе и языках Тернера. Но программисты хотели писать ПМ с пересекающимися паттернами, так что для HOPE+ нашли более-менее понятную систему определения того, какое сопоставление с образцом более точное [Perr91].   
Сопоставление паттернов-констант - более точное, чем сопоставление с переменной. Так что при применении функции 

```
--- f(1, y) <= y; (a)
--- f(x, 2) <= x; (b)
--- f(a, b) <= a * b; (c)
```

так `f(1,3)` будет выбрано уравнение (a), в случае `f(5,2)` уравнение (b), в случае `f(3,4)` уравнение (c), а применение `f(1,2)` вызовет ошибку во время исполнения потому, что ни один из вариантов (a) и (b) не подходит лучше другого. Компилятор предупреждал о возможности такого исхода во время компиляции.   
Эдинбургской группе разработчиков HOPE не пригодилась ленивость и в SML не попали ленивые списки из HOPE. Лондонская группа посчитала ленивость полезной, так что в HOPE+ все конструкторы стали ленивыми. Правда, функции все равно строгие, каждый параметр вычисляется до первого конструктора.   
Это сочетание сегодня выглядит довольно необычно. И противоположно популярным рекомендациям писать на Haskell ленивые функции и типы данных со строгими полями.   
В другом HOPE+ можно было добиться более привычного в наше время поведения. В другом HOPE+?   
Между компиляторами HOPE для обычных машин и машин параллельных было мало общего. Разумеется, это привело к тому, что они имплементировали разные языки.   
В параллельном HOPE+ были аннотации ленивости [Glyn90] и можно было форсировать "позвоночник" структуры данных без форсирования элементов:

```
dec length : !# ST SN #! list alpha -> num;
```

Или вычислить всю структуру:

```
dec sum : !# ST IN #! list num -> num;
```

А можно было и сделать функции ленивыми:

```
dec append : !# ST(WH,UN) #! (list alpha # list alpha) -> list alpha;
```

Здесь `WH` - аннотация поведения по умолчанию, вычисления до первого конструктора. А `UN` - означает ленивый аргумент. Так что параллельный HOPE+, пусть и с помощью аннотаций, но мог быть более обычным в наше время ленивым языком.   
Практически до самого конца проекта в параллельном HOPE+ был [Robe89] и более привычный для нас сегодня паттерн-матчинг. Паттерны могли пересекаться и результат сопоставления зависел от последовательности уравнений. Прочие отличия были менее интересными недоработками. Взаимная рекурсия в `let` и `where` и числа с плавающей точкой не были имплементированы.   
Отличий вариантов HOPE+ от HOPE не достаточно, чтоб наш обычный пример выглядел существенно иначе:

```
infixr :: : 5;
data list alpha == nil ++ alpha :: list alpha;

dec map : (alpha -> beta) # list alpha -> list beta;
--- map(f, nil) <= nil;
--- map(f, x::xs) <= f x::map(f, xs);

map(lambda x => x+y,[1,2,3]) where y == 1 end;
```

Он мог бы быть полностью идентичным, но мы не ставили перед собой такой цели.   
Для тех, кто не был убежден в ненужности Пролога Лондонские разработчики HOPE планировали логические расширения. И даже имплементировали, хоть и не в основном, рабочем компиляторе.   
Возможно, делать "функции" со многими результатами по умолчанию - не самая хорошая идея. Но почему бы не добавить в язык специальную нотацию для этого? Такая нотация - ЦФ-выражения уже была в языках Тернера и в NPL. И планировалась для HOPE, но долгое время продолжала только планироваться.   

```
filter(p,xs) <= {x | x in xs : p x}
```

Правда, ЦФ-выражения, list comprehensions - не встроенный Пролог, а скорее какой-то из анти-Прологов Сассмана и Хьюита. Но что если встроить именно Пролог?   

```
{(l1, l2) with l1, l2 | l1 <> l2 = [1, 2]}
{([], [1, 2]), ([1], [2]), ([1, 2], [])} : set(list num # list num)
```

Теперь функции можно применять слева от `=` как в более выразительных языках алгебраической спецификации. Но пока что только внутри новых "абсолютных абстракций множеств" [Darl87] [Darl89].   
Существует ли список из двух элементов?

```
{l with l | length l = 2}
```

Да!

```
{u :: (v :: nil)} : set(list alpha)
```

В функциональных языках Эдинбургской исследовательской программы такие расширения не прижились. Они сыграли более заметную роль в HOPE-фикации Пролога. Но это уже другая история.   

### Граф 0

В апреле 84-го при поддержке директората Alvey состоялась встреча представителей академии и индустрии на которой обсуждали общую вычислительную модель для параллельных вычислений. Участники встречи разделились на два лагеря. Одни считали, что общий промежуточный язык будет иметь достаточно плюсов чтоб скомпенсировать возможные проблемы с производительностью. Другие считали, что  производительность слишком важна для таких компромиссов. Сторонники единого промежуточного языка победили. Победили в первой битве, но смогли ли они победить в войне? Давайте выясним.   
Единый промежуточный язык назвали DACTL (Declarative Alvey Compiler Target Language). DACTL должен [Glau87] был подходить для трансляции в него таких языков как HOPE, Prolog и даже Lisp. Промежуточный язык также должен был подходить для исполнения на параллельных машинах программы Алви, и это не только Flagship-машина. О другой спецмашине программы мы еще расскажем позднее.   
Язык должен был быть достаточно низкоуровневым чтоб описывать детали порядка вычисления и где происходит копирование, а где - переписывание для разделения результатов. Но не слишком низкоуровневым. Быть ФЯ, о свойствах кода на котором легко рассуждать и свойства которого легко доказывать.   
Директорат Алви организовал команду по разработке DACTL в июле 84-го. Процесс создания DACTL пошел в Университете Восточной Англии (University of East Anglia) под руководством Ронана Слипа (Ronan Sleep) и Джона Глоерта (John Glauert).   
Слип был соавтором героя прошлой части Келлера. Второй руководитель был связан с событиями предыдущих частей сильнее.   
Глоерт [Glau1] [Glau2] получил степень бакалавра в Кембридже в 76-ом. Степень магистра он получал в Университете Манчестера, где в это время шли работы над Dataflow-машиной, которую мы упоминали в прошлой части. Магистерская диссертация была об имплементации ФЯ с рекурсией на Dataflow-машине.   
Вернувшись после этого в Кембридж Глоерт защитил там докторскую диссертацию. Затем он вернулся в Манчестер и снова поработал там в Dataflow-проекте, над дизайном и имплементацией SISAL. После всего этого, в 84-ом году Глоерт начал работу в Университете Восточной Англии.   
DACTL планировали создать за три итерации [Glau87]. Описание первой итерации Dactl0 было готово в мае 85-го. В сентябре 85-го состоялся первый релиз образцового интерпретатора [Glau91].   
Финансирование от Alvey стало поступать в университет с мая 85-го. DACTL-проект был третьим по размеру спецмашинным проектом Алви. Выделенные на него средства [Blac85] - 360тыс. фунтов или 1.9 миллионов долларов в 2025 - были несопоставимы с первым по размеру проектом Flagship, но вполне сопоставимы со вторым.   
DACTL - язык уравнений с паттерн-матчингом [Glau87]

```
PROGRAM test;
IMPORTS lists;
ATOM append;
RULE
<append nil $x> => !$x;
<append <cons $h $t> $x> := <cons $h !<append $t $x>>;
<append $a $b> := !<append !$a $b>;
REWRITE !<append <cons 1 nil> <cons 2 nil>>;
ENDPROGRAM test;
```

паттерны в Dactl лево-линейные (имена переменных не могут повторяться в паттерне для обозначения равенства).   
Все вычисления явно обозначаются `!` и если восклицательного знака нет - это не вызов функции, а просто данные, конструкторы. Переписывание на месте `:=` и возвращение копии ссылки `=>` тоже явно указывается.  
Вся эта получившаяся явность авторам быстро разонравилась и они решили сделать следующую версию менее явной или, по крайней мере сделать указания менее многословными и более высокоуровневыми.  
И если не хватало проблем со взаимодействием между проектами от того, что промежуточный язык разрабатывается в отдельном проекте от имплементирующих его машин и компилирующих в него компиляторов, то теперь проект разработки промежуточного языка стал еще и международным.

### Барендрегт против лямбды

Университет Восточной Англии [Glau87] [Brus87] объединил усилия с голландским проектом по созданию параллельной машины редукции (Dutch Parallel Reduction Machine Project) под руководством более известного другими своими работами Хенка Барендрегта (Hendrik Pieter Barendregt).   
Совместно они разработали язык LEAN (the Language of East Anglia and Nijmegen), который стал основой для Dactl1. Да, это означает, что у разработки Dactl было более трех итераций, но это, наверное, самое безобидное отклонение от первоначальных планов. Этот LEAN не имеет никакого отношения к современному языку Lean.   
Как было принято в 80-х, Нидерланды тоже решили ответить на японский вызов [Bare87]. Так что в ноябре 1984 три исследовательских группы университетов Амстердама, Неймегена и Утрехта
начали совместный проект, спонсируемый министерством науки и образования. 
Первая фаза, продолжающаяся до конца 87-го должна была ответить на вопрос: возможно ли и реалистично ли построить эффективную машину параллельной редукции? Эта цель может показаться не очень амбициозной но голландский ответ на японский вызов был довольно серьезным. Разрабатывались как минимум две специальные машины. Philips Laboratories работали над Distributed Object Oriented Machine, а университеты над Experimental Parallel Reduction Machine.   
Что более важно для нашей истории - разрабатывали семейство быстрых имплементаций функциональных языков для обычных машин, которое если и не живет в полном смысле этого слова, то по крайней мере влачит жалкое существование до сих пор.   
Первая имплементация семейства имплементировала не язык LEAN, а его чисто-функциональное подмножество без операции переписывания `:=` - язык CLEAN.   
Некоторые читатели, возможно, знают современный язык с таким названием - чисто-функциональный ленивый язык с классами типов, который известен приличной производительностью, которая достигается не без помощи "плоских" объектов и уникальных типов, использующихся для изменения массивов на месте. Это не тот язык о котором мы рассказываем сейчас. В нем нет массивов, классов типов, уникальных типов да и типов вообще.   
Нельзя сказать, что CLEAN 87-го года не имеет никакого отношения к современному, как было в случае LEAN. У первого и современного CLEAN общие авторы Марко ван Ээкелен (Marko C.J.D. van Eekelen) и его научрук Маринус Плазмейер (Marinus J. Plasmeijer). Оба языка являются продуктами одной исследовательской программы. Но один не превратился в другой путем добавления тех фич, которые сегодня выделяют Clean из множества прочих ФЯ. Синтаксически они настолько различны, насколько возможно в обсуждаемую эпоху HOPE-фикации. Первый CLEAN как LML, HOPE и SML происходят от поздних версий NPL с характерными разделителями между уравнениями одной группы, а современный Clean как Haskell и языки Тернера от раннего NPL с более легковесным синтаксисом.
Мелкие отличия от прочих поздних NPL-ей CLEAN 87 по видимому унаследовал от предыдущего ФЯ Барендрегта под названием TALE (Typed Applicative Language Experiment) [Bare86] на момент описания в 86-ом году Он не был имплементирован и не было конкретных планов имплементации.   

```
list $ t = rectype ls: (* |(t, ls)).

Def:
map f <>    -> <>;
map f (a:b) -> (f a) : (map f b).

map (`x -> x + y) <1, 2, 3> where y = 1 end
```

Так выглядит TALE, а (C)LEAN - намного проще [Brus87].

```
Map f Nil -> Nil |
Map f (Cons a b) -> Cons (Ap f a) (Map f b);
```

Планы имплементации CLEAN были. И та их часть, которая касалась обычных компьютеров была осуществлена.  
Разработчики CLEAN считают, что хорошую имплементацию ФЯ на обычном железе может сделать и не так просто, но сделать можно. В середине 80-х эта проблема решена. Имплементаторы ФЯ теперь знают как эффективно реализовать ленивость, возвращение функций из функций и рекурсию. Если оптимизировать хвостовые вызовы, использовать редукцию графов и избегать ее где это возможно, заменяя обычными вычислениями на стеке, то можно добиться производительности сравнимой с имплементациями обычных императивных языков.   
Разработчики CLEAN считают, что не все еще хорошо со сборкой мусора и анализом строгости - было бы неплохо поработать на этих направлениях. И тут сложно с ними не согласиться.   
Существенно позднее авторы языка напишут, что он разрабатывался с самого начала проекта в 84-ом году, проектирование первой версии закончилось в 85-ом, первый компилятор был написан в 86-ом [Plas95]. В 87-ом году вышла первая дошедшая до на статья, в которой описывается версия 4.0 компилятора и языка, который определен только своей имплементацией. Версия современного Clean меньше, но это потому, что следующей версией после 4.0 была 0.5. Этот компилятор был первым публичным релизом в том же 87-ом году [Plas01].
Как и их лондонские коллеги, авторы CLEAN начали с компилятора для VAX-11, но более интересные результаты получили продолжив работу компиляторами для MC68K.   
(C)LEAN был задуман как промежуточный язык, так что сначала в нем не было `let`, `where`, локальных функций и даже лямбд. Что может выглядеть неожиданно, принимая во внимание то, какими работами Барендрегт более известен.
Как ни странно, Барендрегт и остальные авторы (C)LEAN считают, что промежуточным языком для имплементаций ФЯ должна быть не лямбда с расширениями, а язык уравнений.  
Лямбда-исчисление часто представляется как сама собой разумеющаяся вычислительная модель для ФЯ, пишут [Brus87] они, вот только большинство имплементаций основаны не на лямбда-исчислении, а на комбинаторной логике (SKI-интерпретатор Тернера, G-машина, CAM), а для представления функциональных программ используются графы, лишние вычисления в которых предотвращаются разделением подграфов. ПМ очень важен в ФЯ, так что имеет смысл включить его в вычислительную модель.   
Получается, что если мы хотим вычислительную модель для ФЯ близкую к имплементации, то лямбда-исчисление уже совсем не выглядит очевидным выбором.
Это авторы (C)LEAN дискутируют с теми, кто имплементировал HOPE на обычном железе и с другим машинистом, будущим важным героем нашей истории. К этому мы еще вернемся.   
Первоначально планировалось, что компилятор CLEAN станет компилятором LEAN поддержав мутабельность. И может быть даже логические переменные, приблизившись к DACTL.   
Питер Копман (Pieter Koopman) и др. показали [Brus87], что в Clean можно компилировать SASL, TALE и OBJ2 - новую версию языка алгебраической спецификации OBJ0, о которой мы рассказывали в нулевой части. Главным же достижением должен был стать компилятор нового языка Тернера. Этим планам не суждено было сбыться и к причинам мы еще вернемся в следующей главе с новыми приключениями Тернера. Но и остальные перечисленные компиляторы не стали чем-то большим, чем эксперименты. CLEAN как промежуточный язык не состоялся.   
Проблема в том, что CLEAN пока что не очень хороший промежуточный язык. Он не поддерживает локальные функции оставляя лямбда-лифтинг разработчикам транслятора в CLEAN. Не поддерживает CAF что важно для ленивых языков. Но хуже всего то, что CLEAN компилируется в медленный код. Код сгенерированный компилятором Lazy ML работает в 7-9 раз быстрее, в зависимости от микробенчмарка.  
Но авторы компилятора CLEAN не унывают. Они считают, что смогут существенно улучшить производительность кода и собираются сконцентрировать свои усилия на этом. Больше использовать стек, лучше компилировать ПМ, умнее управлять памятью.   
Важную роль в отставании от LML сыграло то, что первые версии CLEAN хоть и были языком уравнений с самого начала, еще не были полностью HOPE-фицированными.   
Но CLEAN стал полностью HOPE-фицированным языком до конца 80-х годов. В это время еще не угасла надежда на то, что CLEAN будет промежуточным языком для какого-то компилятора кроме CLEAN, но появилось движение в сторону более-менее полноценного языка, хоть и все еще простого [Gron90]. И CLEAN оброс соответствующими фичами [Nock91].

```
MODULE Test;
TYPE

:: List x -> Cons x (List x) |
   List x -> Nil ;

RULE

:: Map (=> x y) [x] -> [y] ;
   Map f [] -> [] |
   Map f [a | b] —> [f a | Map f b] ;
```

знакомые с современным Clean могут заметить тут пару знакомых синтаксических деталей, но это добавление деталей никогда не сложится в CLEAN похожий на современный. Современный будет сделан более-менее с нуля спустя годы, но это уже другая история.   

### Самый известный птеродактиль на Панталасском театре   

После совместной с голландцами "фундаментальной переработки вычислительной модели" в Университете Восточной Англии разработали новую версию DACTL основанную на LEAN.   
Спецификация ядра Dactl была готова в марте 87, принята Flagship вскоре после того. Черновик описания новой версии Dactl появился в июне 87-го и готовое описание в декабре 87-го.
Никаких фундаментальных переработок больше не было, так что последняя версия Dactl не особенно отличалась от второй и была готова в начале января 89-го. Образцовый интерпретатор - вскоре после этого [Glau91].   
Теперь DACTL выглядел так:

```
MODULE Test;
IMPORTS Lists;
SYMBOL REWRITABLE Append;
RULE
    Append[Cons[h t] y] => #Cons[h ^*Append[t y]] |
    Append[Nil y] => *ForceList[y] ;
    Append[x y] => #Append[^*x y] ;
ENDMODULE Test;
```

`|` - разделитель между уравнениями, порядок которых не важен. И `;` - разделитель между уравнениями, порядок которых важен.  
Аннотации порядка вычисления теперь показывают зависимость одних промежуточных результатов от других, так что ленивый код требовал меньше аннотаций и даже меньше уравнений:

```
Append[Cons[h t] y] => *Cons[h Append[t y]] |
Append[Nil y] => *y ;
```

Как видите, язык хоть и напоминает (C)LEAN, но не является просто им с дополнительными аннотациями.   
Dactl разрабатывался итерационно для того, чтоб учитывать опыт его использования и для приобретения этого опыта использования Dactl0 и Dactl1 в Университете Восточной Англии и не только написали несколько трансляторов.
Промежуточный язык должен был подходить и для трансляции логических языков, так что Джордж Пападопулос (George Papadopoulos) написал трансляторы Parlog [Papa89] и GHC [Glau88] в DACTL. GHC не имеет ничего общего с более известным и релевантным для нашей истории Glasgow Haskell Compiler и в данном случае расшифровывается Guarded Horn Clauses.  
Компания Harlequin, которая уже упоминалась в нашей истории, ей Радиолокационная Лаборатория заказала компилятор SML, для проекта Flagship писала в 87-ом году Harlequin Flagship Common Lisp Compiler.   
Более соответствующими теме нашей истории компиляторами были три транслирующих HOPE-фицированные ФЯ в DACTL.
Один из авторов DACTL в университете Восточной Англии Ричард Кеннвей (Richard Kennaway) написал в 88-ом году транслятор CLEAN. Этот язык в описываемое время был довольно минималистичным и близким к DACTL, так что компилятор вышел не самым сложным. Второй восточно-английский компилятор был существенно сложнее.   
Новый важный герой нашей истории Кевин Хаммонд (Kevin Hammond) написал транслятор языка PSML. Что означает Parallel Standard ML. Как обычно бывает в этой главе, стандартный ML был не совсем стандартным и относился к SML версии 2 (т.е. образца 88-го года) на основе которого был сделан, примерно так же как первоначальный Lazy ML относился к LCF/ML. PSML - декларативное подмножество Standard ML. Из этого языка убраны все императивные конструкции: циклы, изменяемые ссылки и большинство функций ввода-вывода. Исключения не убраны полностью, а заменены на ошибки-значения, похожие на те что в Hope+ [Hamm89b].   
PSML компилировался сначала в DACTL0 [Glau87]
, а потом в в DACTL1, Хаммонд экспериментировал и со строгой и с ленивой версией языка. Хаммонд писал компилятор в рамках работы над диссертацией и защитил её [Hamm91] в ноябре 88-го.   
Третьим транслятором был уже упомянутый нами лондонский компилятор параллельного HOPE+. Правда, компилировал он не в DACTL, а в его подмножество, поддерживаемое Flagship-машиной. Подмножество называлось MONSTR.   
Как и трансляторы в CLEAN, эти экспериментальные компиляторы не были важными для нашей истории. DACTL тоже был не особенно удачным промежуточным языком. Идея единого промежуточного языка восторжествовала на этапе планирования, но не выдержала испытаний на этапе имплементации. Вместо единого языка получилось множество. Больше, чем получилось бы, если бы каждый проект спецмашины имел собственный язык с самого начала.
Существовали только две полных имплементации DACTL: университетский образцовый интерпретатор и транслятор в C под названием ICL IIS, который написали в ICL - компании, строившей прототипы Alice и Flagship.   
Транслятор в C может для нашей истории быть важнее всех этих спецмашин вместе взятых. Но не этот. На новых рабочих станциях SUN, которые были в 2-3 раза быстрее VAX-11/780 он выдавал только 1000 nfib в секунду. Чуть более чем в два раза быстрее, чем образцовый интерпретатор. И на десятичные порядки медленнее, чем последнее слово техники функционального компиляторостроения.   
Оба спецмашинных проекта директората Алви нашли способ не использовать DACTL. И если Flagship имплементировал подмножество, только то, что хотел, то другая Алви-машина отказалась от промежуточного языка уравнений с ПМ полностью, выбрав расширенную лямбду. Но это уже другая история.   

### Негативное пространство.

Саймон Пейтон-Джонс (Simon Loftus Peyton Jones) [SPJ18], как и его шведский коллега Августссон, относится к тому поколению имплементаторов ФЯ, которое познакомилась с компьютером еще в школе. В этой же школе учился функциональный машинист из прошлой части Томас Кларк. В результате этого опыта у Кларка и Пейтон-Джонса появилось желание разрабатывать компьютеры. И разработка компьютеров - это не те работы, которыми Пейтон-Джонс известен. Но всему свое время.  
После школы, в Кембриджском университете Пейтон-Джонс повстречал ещё больше героев нашей истории: Хьюза и Фейрберна.   
В Кембридже, как и в университете Чалмерса, пока что не было компьютерных наук как специальности. Так что Пейтон-Джонс сначала изучал математику. Но математика показалась ему слишком сложной, поэтому он стал изучать электротехнику. Компьютерные науки, впрочем, успели появится достаточно рано чтоб Пейтон-Джонс получил и такую специальность за один 79-80 год.  
На то, что Пейтон-Джонс заинтересовался не просто разработкой компьютеров, а именно специальных ФП-машин, повлияли уже упоминавшиеся нами преподаватель Артур Норман от которого Пейтон-Джонс впервые узнал о функциональном программировании, Тьюринговская лекция Бэкуса и, разумеется, статья Тернера.  
Как и на его шведских коллег, на Саймона Пейтон-Джонса произвела впечатление статья Тернера про комбинаторный интерпретатор. Дипломная работа Пейтон-Джонса была сравнением комбинаторного интерпретатора с SECD. Сам СПЖ считает ее не особенно полезной потому, что из сравнения наивных интерпретаторов не стоит делать далеко идущих выводов. На основе этого диплома была написана уже упомянутая нами в прошлых частях статья.   
Пейтон-Джонс не хотел работать над докторской диссертацией, он хотел работать в индустрии. Об этом он вскоре пожалел - работа в индустрии ему не особенно понравилась, и через два года он вернулся в академию.   
В 82-ом Пейтон-Джонс стал читать лекции в Университетском колледже Лондона (University College London). Но для того чтоб преподавать надо же защитить диссертацию? Не в те времена. Внезапно оказалось, что нужно учить компьютерным наукам много-много студентов, а преподавателей не хватает. Так что Пейтон-Джонс мог работать, а диссертацию защитить когда-нибудь потом.   
Для того чтоб освоить исследовательскую работу, Пейтон-Джонс написал уже упомянутую нами статью про написание Yacc на SASL. Пока работал над ней, он общался с Тернером и даже называет Тернера своим неформальным научным руководителем.   
В апреле 83-го Саймон Пейтон-Джонс организовал [SERC83] коллоквиум по декларативному программированию в Университетском колледже Лондона. Там Йонссон впервые выступил с докладом о G-машине, о том как быстро можно редуцировать графы, а избегать их редукции - еще быстрее.   
И именно этим Пейтон Джон со своими коллегами Клеком (Christopher D. Clack), Салкилдом (Jon Salkild) и Харди (Mark S. Hardie) и стали заниматься, когда Университетский колледж Лондона начал второй по величине проект директората Алви по созданию ФП-машины. Проект назвали GRIP (Graph Reduction In Parallel). Индустриальными партнёрами были все та же ICL и High Level Hardware Limited.
На второй по величине проект выделили в десятки раз меньше денег, чем на первый - всего 480 тыс. фунтов (два с половиной миллиона долларов в 2025) [Blac85], так что подходы исполнителей проектов просто обязаны были существенно отличаться.   
Но GRIP-машина отвечала на проблемы ALICE с производительностью схожим с Flagship образом. Правда, хватало и различий [SPJ88a].   
В GRIP осталось разделение на вычислительные элементы и элементы разделяемой памяти. Вычислительные элементы PE (Processing Element) - настолько обычные компьютеры, насколько это возможно. С новыми процессорами Motorola 68020 и большой локальной памятью, недоступной остальным процессорам компьютера. Сначала 128Кб но планировалось увеличение до 512Кб [SPJ87a] а затем и 1Мб [SPJ88a]. Обычные компьютеры умеют делать очень хорошо и дешево, и с каждым годом все лучше и дешевле, очень важно воспользоваться этими возможностями.   
И что более важно для нашей истории, схожесть вычислительного элемента с обычной рабочей станцией означает, что участники проекта GRIP разрабатывали способы имплементации ФЯ применимые на обычной рабочей станции.   
Но где же тогда специальное в этой спец-машине? Специальным микропрограммируемым железом являются только блоки разделяемой между процессорами памяти IMU (Intelligent Memory Unit). Эти микропрограммируемые компьютеры, оптимизированные для перемещения данных и операций с указателями, собирали мусор и предоставляли доступ к разделяемой памяти не как к массиву слов, а к операциям над графами и их элементами.   
Авторы считают основным недостатком то, что работа с памятью и особенно кэшами в обычных компьютерах лучше и быстро совершенствуется. Специальный компьютер блока памяти не может полноценно использовать эти успехи. Авторам не очевидно, что специальность компьютера сможет компенсировать это отставание.   
Эта организация памяти еще больше мотивирует минимизацию изменений графа. Переписыватель графа, чтоб быть эфективным переписывателем, переписывает только в том случае, если без переписывания будет потеряно разделение. Это мотивировало работу разработчиков GRIP над усовершенствованием способов компиляции ФЯ.  
В блоке разделяемой памяти до 4 миллионов 40-битных слов.   
Для соединения блоков используется уже существующая обычная шина, в отличии от прочих разработчиков спецмашин, разработчики GRIP не собирались связываться и с этим.   
Но к существующим шинам не подключить много блоков, так что структура становится двухуровневой. 4 вычислительных блока и один блок разделяемой памяти объединяются на одной плате, которых может быть до 20. К блоку разделяемой памяти такой платы есть доступ и с других плат, но более медленный.  
Так что на втором уровне блоки все-таки объединяются как во Flagship, но в каждом больше процессоров у каждого из которых больше собственной памяти.    
Первый прототип с одной группой блоков планировали построить в середине 87-го, а с несколькими группами - в конце лета того же года [SPJ87a]. Не позднее 88-го первый прототип, смонтированный накруткой, был готов. Новый прототип с печатными платами ожидался в середине 88-го.   
ФЯ имплементировались на этих вычислительных блоках с помощью суперкомбинаторов. Первоначальная имплементация была наивной, но не позднее 87-го года для этого использовали наработки Йонссона - G-машину [SPJ87a]. И это не последняя наработка Йонссона, которую использовали в GRIP.   
До 87-го года разработчики GRIP собирались имплементировать DACTL. И использовать компиляторы в DACTL, написанные остальными Алви-проектами [SPJ87a].   
Но оказалось, что DACTL не так легко имплементировать. Никто не сделал полноценной имплементации. Даже Flagship, и этот проект намного богаче GRIP. Нужно было что-то менее амбициозное. Этим неамбициозным чем-то стал FLIC (Functional Language Intermediate Code) [SPJ88b].  
Над этим промежуточным языком работали еще и в Университете Уорика (University of Warwick), и FLIC - один из ранних примеров языка, который разрабатывали обсуждая в электронной почтовой рассылке. Но в университете Уорика наработали не много полезного.   
Авторы пишут, что общий промежуточный язык может быть решением проблемы большого числа функциональных языков. Таким решением, которое не заставляет их унифицировать и позволяет им сохранить их сильные стороны.   
Ирония в том, что средство спасения от необходимости заменять многообразие функциональных языков на один универсальный язык придумывал разработчик языков, более известный своей работой над универсальным языком для замены многообразия ФЯ.   
Похоже, что авторы хотели подтолкнуть образование экосистемы вокруг FLIC. Вроде той, что тогда же пытались построить вокруг DACTL. По крайней мере для функциональных языков. В Лондоне не собирались поддерживать на GRIP ничего кроме функциональных языков, но другая группа исследователей в университете Эссекса работала над или-параллельным Прологом для этой машины.  
Для них легкой жизни не обещали, но авторы пишут, что ФЯ транслировать во FLIC просто! Но никто не успел написать практичный транслятор ФЯ во FLIC за них.   
И это было проблемой. Flagship мог себе позволить разработку двух компиляторов, но GRIP не может себе позволить даже одного. По крайней мере, пока не может.   
Но если написание собственного компилятора требует слишком много усилий, то изменение существующего компилятора может быть вполне по силам.   
Пейтон-Джонс и др. использовали язык и компилятор Lazy ML Августссона и Йонссона. Так что этот проект тоже получился международным. Но если в случае CLEAN/Dactl все закончилось международными согласованиями, после которых все делали что-то свое, то GRIP просто использовал то, что уже было сделано в Швеции. Согласования были позже, но это уже другая история.   
Авторы пишут что использовали компилятор LML потому, что имели доступ к его коду. И выбор в это время был по видимому сильно ограничен. Особенно для тех кому нужен чисто функциональный язык и для ценителей работ Тернера.   
Для компилятора LML написали бэкенд, транслирующий во FLIC. И легкость трансляции из промежуточного кода компилятора LML должна была сыграть важную роль в определении того, как FLIC выглядел. Функциональные языки - обычно лямбда с расширениями, пишут его авторы, так что все их можно компилировать в лямбду с несколько меньшим числом расширений.   
Ну, допустим, что в это время ФЯ - уже обычно уравнения с паттерн матчингом, тут правы скорее авторы CLEAN. Но вот промежуточные языки у реально существующих и более-менее зрелых имплементаций все ещё лямбда с не особенно большим числом расширений. И FLIC - язык идейно родственный промежуточным языкам IF1 Манчестерской dataflow-машины и FP/M Лондонского компилятора HOPE+ для обычных машин. Но немного более универсальный и высокоуровневый.  
Но главное то, что промежуточный язык компилятора Lazy ML - это сам Lazy ML. Но не Lazy ML второй половины 80-х, большой HOPE-фицированный язык уравнений с ПМ, а его минимальное подмножество - лямбда с расширениями.   
Имплементации ПМ в компиляторах уже есть, разработчику спец-машины можно не имплементировать все возможные его версии, которых в то время было больше, чем сегодня.   
Ирония в том, что это восстание против языков уравнений произошло потому, что разработчик компиляторов, который более известен имплементацией большого и сложного языка уравнений, не хотел имплементировать не такой большой и менее сложный язык уравнений.   
Хотел или не хотел, правда, не так важно как то, что не мог. Альтернативное настоящее в котором роль Core в сегодняшнем GHC играет совсем не сегодняшний CLEAN было возможно, но такой исход не был особенно вероятным.   
Важно, правда, отменить, что FLIC - это не Core. Да, FLIC - лямбда-исчисление с расширениями. Язык ленивый по умолчанию, но с помощью аннотаций можно писать энергичный код. Функции каррированы по умолчанию, способа объявлять некаррированные функции многих параметров нет. Но FLIC должен быть машиночитаемым. Хотя код на FLIC должен быть корректно типизирован, аннотация типов не требуется, а их проверка не производится. Компилирующий во FLIC компилятор может сохранить информацию о проверенных им типах только в аннотациях как метаданные.   
Во FLIC нет АлгТД и даже одноуровневого ПМ. Есть только структуры с полями и тегом и функции для их разбора. Такой код на языке уравнений

```
f (LEAF x) = g x
f (NODE t1 t2) = h t1 t2
```

нужно транслировать в такой FLIC

```
= (f) (\x CASE 2
            (UNPACK 1 g x)
            (UNPACK 2 h x) x)
```

Во FLIC есть развитая система аннотаций. Авторы GRIP - энтузиасты аннотаций, которые не изменяют результата исполнения кода, но помогают сделать его быстрее. Пионером такого подхода был Уоррен, но в ФЯ он не стал распространенным до спецмашинных Алви-проектов.   
Существенное преимущество ФЯ в том, пишут авторы GRIP, что параллелизм в них неявный и аннотации вообще говоря не требуются. Разработчики GRIP написали для компилятора обнаружение таких возможностей для параллелизма с помощью анализа строгости. Но они все равно имплементировали такие аннотации и пользовались ими. Аннотации заметно влияли на производительность.   
Но аннотации для LML, похоже, серьезно отставали от аннотаций для FLIC. Так один из пользователей модифицированного компилятора пишет [Trin89] как он транслировал LML во FLIC и расставлял аннотации строгости и параллелизма уже только в сгенерированном FLIC-коде.   
На этом закончена история о том, как Саймон Пейтон-Джонс успешно избегал работы над тем, чем он как раз известен. Пока, наконец, не перестал избегать. Но это уже другая история.   

### День зависимости

Ответом правительства США на японский вызов была DARPA Strategic Computing Initiative [Stef85]. Десятилетий план, анонсированный осенью 83-го. 300 миллионов долларов ($976 миллионов 2025) на первые три года.
Это был обычный ответ. Но был ещё и ответ необычный. Необычным американским ответом на японский вызов было создание MCC (Microelectronics and Computer Technology Corporation) [Peck86]. Этот, в отличие от японского проекта машины пятого поколения и Алви - полностью частный. Да, 21 коммерческая компании вроде Motorola и AMD и, почему-то, Локхид и Боинг, готовы были не получать деньги на ответы японцам, а даже тратить свои. От государства требовалось пока что только разрешить создавать такие консорциумы, запрещённые в то время антимонопольным законодательством. Что было сделано в 84-ом.   
Японская инициатива была, правда, только одной из угроз. Другой была IBM. 21 компания хотели совместно создать что-то вроде Белл Лабс AT&T или Йорктаун Хайтс IBM, про которую мы не раз писали в нулевой части. На свой ответ они планировали тратить сопоставимые средства - 80 миллионов долларов (237 миллионов в 2025) в год к концу десятилетия.   
Лаборатории MCC расположились в Остине, где как раз в это время закрыли ARC, про который мы писали в прошлой части. Готовность отвечать Японии ARC не помогла, но отдельные исследователи перебежали оттуда в MCC.   
Масштабы ответа впечатляют, но они не конвертируются в серьёзный вклад в нашу историю. Ответ японцам, как обычно, означал - делать больше того, что и так уже делали. И мало кто делал что-то связанное с Эдинбургской программой. А те, кто делали - делали не особенно самобытные вещи. Которые ещё и потеряли самобытность в ходе HOPE-фикации.   
Посмотрим, например, на организованную MCC конференцию по редукции графов, прошедшую осенью 86-го [Fase87].   
Организаторами были наш старый знакомый по предыдущей части Келлер и новый герой нашей истории Джозеф Фазель (Joseph H. Fasel) из Лос-Аламосской национальной лаборатории (Los Alamos National Laboratory).    
Доклады работавшего над Ponder Фейрберна, Йонссона про Lazy ML и Худака с коллегами - про имплементации ФЯ для обычных машин и не относятся к теме этой главы.   
Доклад героя нулевой главы Гогена про очередную версию его языка алгебраической спецификации, глава про который и прочие родственные Эдинбургским ФЯ направления ещё впереди.  
Среди докладчиков преобладают европейцы: разработчики ALICE и Манчестерской Dataflow машины. Французской специальной машины MaRS и представители Голландского проекта.   
Американские докладчики релевантные для этой главы и нашей истории в целом это уже знакомые нам разработчики FEL Келлер с коллегами, разработчики Id Арвинд с коллегами и новый герой Кибурц (Richard B. Kieburtz).
Кибурц работал в Орегоне над моделированием аппаратной G-машины [Kieb86] [Kieb87]. Кибурц, как и Пейтон-Джонс, использовал модифицированный компилятор Lazy ML Йонссона и Августссона.   
Как и другие разработчики (стимуляторов) специального железа, Кибурц и др. использовали два симулятора - более детальный и медленный Microsim, пригодный только для исполнения программ в десятки команд и относительно быстрый инструментированный интерпретатор Macrosim. Macrosim написан Бориславом Агапиевым (Borislav Agapiev) на Modula-II и работал "примерно так же быстро, как интерпретатор Лиспа". Раман Теннети (Raman Tenneti) написал компилятор кодов виртуальной машины для VAX-11. Не позднее 86-го.  
Как и разработчики транслятора PSML в DACTL, Кибурц экспериментировал с ленивостью и тестировал и строгие и ленивые версии. Мы уже видели ленивый "Standard" ML и вот, смотрите: энергичный "Lazy" ML. Обе имплементации, конечно, были не особенно серьёзными, даже по меркам этой истории.   
Другие разработчики симуляторов машин Келлер с коллегами работали в 84-ом году над типизированной версией их языка FEL под названием TFEL [Mish85] [Mish84]. Конечная версия HOPE-фикации должна была стать, по видимому, самой буквальной HOPE-фикацией из всех, псевдокод в статье [Mish84] "похожий на TFEL" выглядел как HOPE без `<=` и с применениями функций как в FEL и FP:

```
data integer = zero + + succ[integer]

dec even: integer -> bool
--- even:zero = true
--- even:succ[zero] = false
--- even:succ[succ[x]] = even:x
```

К сожалению, для реконструкции нашего обычного примера недостаточно информации.
HOPE-фикация FEL, правда, не состоялась. В 85-ом году вместо этого заменили FEL на его версию с Лисп-синтаксисом и безо всяких групп уравнений, ПМ и АлгТД под названием RediLisp [Kelle85] [Kelle87].   
Но не все разработчики специальных ФП-машин остались разработчиками симуляторов. Группа Арвинда в МТИ занялась созданием реального компьютера Monsoon, первый прототип которого должен был быть готов в конце лета 88. Но немного задержался.   
Прототип, смонтированный накруткой, заработал в сентябре 88-го. В декабре он уже исполнял скомпилированные программы на Id. В том же 88-ом Motorola стала индустриальным партнёром МТИ по разработке Monsoon [LCS89].   
Тем временем Нихил HOPE-фицировал Id. Эта HOPE-фикация - одна из самых поздних. Описание [Nikh88] нового Id 88.0 было готово в марте 88-го.   
Теперь функциональное подмножество Id, пишет Нихил, сравнимо с современными ФЯ. В Id теперь есть параметрический полиморфизм, определяемые пользователем алгебраические типы данных и паттерн-матчинг для их конструкторов, абстрактные типы данных и лист-компрехеншоны.   
В LCF/ML было три основных способа и стиля именования параметров типов. Их можно было именовать например `*` и `**`, `*a` и `*b`, `*1` и `*2`. В последующих языках с параметрическим полиморфизмом обычно ограничивались каким-то одним. В Lazy ML, SML и CAML оставили второй способ (заменив позднее `*` на `'` в некоторых из них). В Id выбрали третий способ [Nikh88].   

```
type list *0 = nil | (:) *0 (list *0)

typedef map = (*0 -> *1) -> (list *0) -> (list *1)

def map f nil    = nil
|   map f (x:xs) = f x : map f xs

map = { fun f nil    = nil
      |     f (x:xs) = f x : map f xs }

def map f l = { case l of
                  nil    = nil
              |   (x:xs) = f x : map f xs }    

def map f l = {: f x || x <- l }

{ y = 1
  In
  map { fun x = x + y } (1: (2: (3: nil))) }
```

Как видите, авторы Id не стали себя ограничивать и позаимствовали большинство способов разбора АлгТД. Есть и группы уравнений и `case`-выражения и лямбды, которые одновременно поддерживают и несколько веток и карринг, как в CAML и новом GHC Haskell. `:` после открывающей скобки компрехеншона тут означает, что создается список, эта нотация работает и для массивов.   
Поддержку Id 88 добавил в компилятор весной 88-го Джеймс Хикс (James Hicks) [Nikh88b]. ПМ компилировался методом, описанным Вадлером с некоторыми изменениями. Первоначально язык был имплементирован не полностью, не поддерживались проверка типов для всех нововведений и объявления констант на топлевеле, можно было писать только функции с параметрами. Полная имплементация ожидалась к концу лета 88-го.
И по крайней мере проверка типов была имплементирована полностью к осени Шаилом Адитьей (Shail Aditya).   
В 88-ом компилятор модифицировали чтоб генерировать код для Monsoon и решили, что неплохо было бы генерировать его и для обычных машин. Трауб работал над техниками имплементации нестрогих но не ленивых языков на обычных машинах. И в 89-ом году Лина Мурьянто (Lina Muryanto) и Питер Тан (Peter Tan) написали кодогенератор для MC68020, но пока только для подмножества языка [LCS89].   
На этом очередная глава про специальные ФП-компьютеры подходит к концу. Возможно, вклад героев этой главы в историю функционального программирования пока что не выглядит впечатляющим. Но основной их вклад в дело HOPE-фикации еще впереди. Это, впрочем, уже другая история.   

ПРОДОЛЖЕНИЕ СЛЕДУЕТ

Литература
==========

[Nikh88b]: R.S. Nikhil. Computation Structures Group Progress Report 1987-88. Memo-288, 1988, June   
[Nikh88]: Nikhil, R.S. Id (Version 88.0) Reference Manual. Computation Structures Group Memo 284. MIT Laboratory for Computer Science, Cambridge, MA March 1988   
[LCS89]: MIT Laboratory for Computer Science Progress Report 26, Jul 1988 - Jun 1989 https://apps.dtic.mil/sti/tr/pdf/ADA228606.pdf    
[Kelle85]: Keller, Robert M. "Rediflow architecture prospectus." In TR UUCS-85-105. Dept of Computer Science, University of Utah USA, 1985 Aug.   
[Kelle87]: Keller, R.M., Slater, J.W., Likes, K.T. (1987). Overview of Rediflow II development. In: Fasel, J.H., Keller, R.M. (eds) Graph Reduction. GR 1986. Lecture Notes in Computer Science, vol 279. Springer, Berlin, Heidelberg. doi:10.1007/3-540-18420-1_56   
[Mish84]: Prateek Mishra and Robert M. Keller. 1984. Static inference of properties of applicative programs. In Proceedings of the 11th ACM SIGACT-SIGPLAN symposium on Principles of programming languages (POPL '84). Association for Computing Machinery, New York, NY, USA, 235–244. doi:10.1145/800017.800535
[Mish85]: Prateek Mishra and Uday S. Reddy. 1985. Declaration-free type checking. In Proceedings of the 12th ACM SIGACT-SIGPLAN symposium on Principles of programming languages (POPL '85). Association for Computing Machinery, New York, NY, USA, 7–21. doi:10.1145/318593.318603   
[Kieb86]: Richard B. Kieburtz. 1986. Performance measurement of a G-machine implementation. In Proceedings of the Workshop on Graph Reduction. Springer-Verlag, Berlin, Heidelberg, 275–296.   
[Kieb87]: Rchard B. Kieburtz. 1987. A RISC architecture for symbolic computation. In Proceedings of the second international conference on Architectual support for programming languages and operating systems (ASPLOS II). Association for Computing Machinery, New York, NY, USA, 146–155. doi:10.1145/36206.36197   
[Fase87]: Fasel, Joseph H. Graph Reduction: Proceedings of a Workshop Santa Fe, New Mexico, USA, September 29-October 1, 1986. Vol. 279. Springer Science & Business Media, 1987.   
[Peck86]: Merton J. Peck, Joint R&D: The case of microelectronics and computer technology corporation, Research Policy, Volume 15, Issue 5, 1986, Pages 219-231, ISSN 0048-7333, doi:10.1016/0048-7333(86)90023-5.   
[Stef85]: Mark Stefik. 1985. Strategic computing at DARPA: overview and assessment. Commun. ACM 28, 7 (July 1985), 690–704. doi:10.1145/3894.3896   
[SPJ88a]: Peyton Jones, Clack, Salkild and Hardie, Functional Programming on the GRIP multiprocessor. in Proceedings IEE International Specialist Seminar on Design and Application of Parallel Digital Processors, pp 116-127. 1988   
[SPJ18]: People of Programming Languages. An interview project in conjunction with POPL 2018. Interview with Simon Peyton-Jones http://www.cs.cmu.edu/~popl-interviews/peytonjones.html  
[SPJ87a]: Peyton Jones, Clack, Salkild and Hardie, GRIP - a high performance architecture for parallel graph reduction, LNCS 274:98-112, ISSN 0302-9743, Springer 1987.  
[SPJ88b]: S. L. Peyton Jones. 1988. FLIC—a functional language intermediate code. SIGPLAN Not. 23, 8 (August 1988), 30–48. doi:10.1145/47907.47910   
[Trin89]: Phil Trinder, A FUNCTIONAL DATABASE, PRG82, 1989.   
[Bare87]: Barendregt, H.P., M.C.J.D. van Eekelen, P.H. Hartel, L.O. Hertzberger, M.J. Plasmeijer and W.G. Vree. The Dutch Parallel Reduction Machine Project, In Future Generations Computer Systems 3, pp. 261-270. Proceedings of the International Conference on Frontiers of Computing (Amsterdam, December 1987).   
[Brus87]: Brus, T., M.C.J.D. van Eekelen, M. van Leer, M.J. Plasmeijer and H.P. Barendregt. CLEAN - A Language for Functional Graph Rewriting, In Proc. of Conference on Functional Programming Languages and Computer Architecture (FPCA '87), Portland, Oregon, USA, Kahn Ed., Springer-Verlag, LNCS 274, pp. 364-384.   
[Nock91]: Nöcker, E.G.J.M.H., J.E.W. Smetsers, M.C.J.D. van Eekelen and M.J. Plasmeijer. Concurrent CLEAN, In Proc. of Parallel Architectures and Languages Europe (PARLE '91), Eindhoven, the Netherlands, Aarts, Leeuwen and Rem Eds., Springer-Verlag, LNCS 505, pp. 202-219.   
[Plas01]: Rinus Plasmeijer, Marko van Eekelen, CLEAN LANGUAGE REPORT version 1.3.1 September 2001   
[Plas96]: Rinus Plasmeijer, Marko van Eekelen, Clean Language Report - Version 1.1 - March 1996   
[Gron90]: Groningen J.H.G. van. (1990), ‘Implementing the ABC-machine on M680x0 based architectures'. Master Thesis, University of Nijmegen, November 1990.   
[Hamm91]: Hammond, Kevin. "Parallel SML: a Functional Language and its Implementation in DACTL." (1991).   
[Glau2]: John Glauert: Research Background https://web.archive.org/web/20041207045351/http://www2.cmp.uea.ac.uk/~jrwg/MultiPar/resbg.html   
[Glau1]: John Glauert, Personal profile. https://research-portal.uea.ac.uk/en/persons/john-glauert   
[Hamm89b]: Hammond, Kevin. "Exception handling in a parallel functional language: PSML." In Fourth IEEE Region 10 International Conference TENCON, pp. 169-173. IEEE, 1989.
[Glau87]: Glauert, J. R. W., J. R. Kennaway, and M. R. Sleep. "DACTL: A computational model and compiler target language based on graph reduction." ICL Technical Journal 5, no. 3 (1987): 509-537.   
[Papa89]: Papadopoulos, G.A. (1989). A fine grain parallel implementation of PARLOG. In: Díaz, J., Orejas, F. (eds) TAPSOFT '89. TAPSOFT 1989. Lecture Notes in Computer Science, vol 352. Springer, Berlin, Heidelberg. doi:10.1007/3-540-50940-2_44   
[Glau88]: John R. W. Glauert, George A. Papadopoulos: A Parallel Implementation of GHC. FGCS 1988: 1051-1058   
[Glau91]: Glauert, J.R.W., Kennaway, J.R., Sleep, M.R. (1991). Dactl: An experimental graph rewriting language. In: Ehrig, H., Kreowski, HJ., Rozenberg, G. (eds) Graph Grammars and Their Application to Computer Science. Graph Grammars 1990. Lecture Notes in Computer Science, vol 532. Springer, Berlin, Heidelberg. doi:10.1007/BFb0017401   
[Bare86]: H P Barendregt and M van Leeuwen. 1986. Functional programming and the language TALE. Current trends in concurrency. Overviews and tutorials. Springer-Verlag, Berlin, Heidelberg, 122–207.   
[Darl87]: Darlington, J. (1987) Software development using functional programming languages. ICL Technical J., 5 (3): 492-508   
[Glyn90]: Kewley, John M., and Kevin Glynn. "Evaluation annotations for Hope+." In Functional Programming: Proceedings of the 1989 Glasgow Workshop 21–23 August 1989, Fraserburgh, Scotland, pp. 329-337. London: Springer London, 1990. doi:10.1007/978-1-4471-3166-3_22   
[Robe89]: Robertson, I.B., Way, Wenlock. "Hope+ on Flagship." In Functional Programming: Proceedings of the 1989 Glasgow Workshop, 21-23 August 1989, Fraserburgh, Scotland, p. 296. Springer, 1990. doi:10.1007/978-1-4471-3166-3_20   
[Darl89]: Darlington, J. et al. (1989). A Functional Programming environment supporting execution, partial execution and transformation. In: Odijk, E., Rem, M., Syre, JC. (eds) PARLE '89 Parallel Architectures and Languages Europe. PARLE 1989. Lecture Notes in Computer Science, vol 365. Springer, Berlin, Heidelberg. doi:10.1007/3540512845_46   
[Perr91]: Perry, Nigel. "The implementation of practical functional programming languages." PhD diss., Department of Computing, Imperial College, 1991.   
[Fiel88]: Field, Antony and Peter G. Harrison. “Functional Programming.” (1988).   
[Kean94]: Keane, John A. "An overview of the Flagship system." Journal of Functional Programming 4, no. 1 (1994): 19-45.   
[Acce86]: Accetta, Mike, Robert Baron, William Bolosky, David Golub, Richard Rashid, Avadis Tevanian, and Michael Young. "Mach: A new kernel foundation for UNIX development." (1986): 93-112.   
[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   
[Appe91]: Appel, Andrew W. "Compiling with Continuations." (1991). DOI:10.1017/CBO9780511609619   
[Augu84]: Lennart Augustsson, A compiler for lazy ML. LFP '84: Proceedings of the 1984 ACM Symposium on LISP and functional programming August 1984 Pages 218–227 doi:10.1145/800055.802038   
[Augu85]: Augustsson, L. (1985). Compiling pattern matching. In: Jouannaud, JP. (eds) Functional Programming Languages and Computer Architecture. FPCA 1985. Lecture Notes in Computer Science, vol 201. Springer, Berlin, Heidelberg. doi:10.1007/3-540-15975-4_48   
[Berr90]: Dave Berry, COMP.LANG.ML Frequently Asked Questions and Answers 19 Apr 1990   
[Blac85]: Blackburn,J. F. The Alvey Conference in Edinburgh: A Review of the United Kingdom's Research Program in Computer Science. 1985 Aug 22 https://apps.dtic.mil/sti/tr/pdf/ADA158963.pdf   
[Boye92]: Robert S. Boyer. Frequently Asked Questions about KCL and AKCL. https://web.cecs.pdx.edu/~mperkows/=LISP/kcl   
[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   
[Caml261]: CAML V2-6.1   
[Card82a]: EDINBURGH ML by Luca Cardelli, March, 1982. A README file accompanying the distribution of Cardelli's ML Compiler for VAX-VMS. https://smlfamily.github.io/history/Cardelli-Edinburgh-ML-README-1982_03.pdf   
[Card83]: Luca Cardelli, Pre-Standard ML under Unix, August 14 1983. http://lucacardelli.name/Papers/MLUnix.pdf   
[Card83b]: Luca Cardelli, ML under Unix Pose 0. 9/9/83 http://lucacardelli.name/Papers/MLUnix%20Pose%200.pdf   
[Card83c]: Luca Cardelli, ML under Unix Pose 1, http://lucacardelli.name/Papers/MLUnix%20Pose%201.pdf   
[Card83d]: Luca Cardelli, ML under Unix Pose 2, 10/10/83 http://lucacardelli.name/Papers/MLUnix%20Pose%202.pdf   
[Card83e]: Luca Cardelli, ML under Unix Pose 3, 11/15/83 http://lucacardelli.name/Papers/MLUnix%20Pose%203.pdf   
[Card84]: Luca Cardelli. 1984. Compiling a functional language. In Proceedings of the 1984 ACM Symposium on LISP and functional programming (LFP '84). Association for Computing Machinery, New York, NY, USA, 208–217. doi:10.1145/800055.802037   
[Card84b]: Luca Cardelli, ML under Unix Pose 4, 4/5/84 http://lucacardelli.name/Papers/MLUnix%20Pose%204.pdf   
[Card84c]: Luca Cardelli, A semantics of multiple inheritance. in Semantics of Data Types, International Symposium, Sophia-Antipolis, France, June 1984, Proceedings. Lecture Notes in Computer Science, Vol. 173, Springer-Verlag, 1984, ISBN 3-540-13346-1. pp 51-67.   
[Card85]: Antonio Albano, Luca Cardelli, and Renzo Orsini. Galileo: a strongly typed, interactive, conceptual language. ACM Transactions on Database Systems (TODS), 10(2):230-260, 1985.   
[Card86]: Luca Cardelli. Amber. In Guy Cousineau, Pierre-Louis Curien, and Bernard Robinet, editors, Combinators and Functional Programming Languages, Lecture Notes in Computer Science, Vol. 242, pp 21-70. Springer-Verlag, 1986.   
[Card86b]: Luca Cardelli. The amber machine. In Guy Cousineau, Pierre-Louis Curien, and Bernard Robinet, editors, Combinators and Functional Programming Languages, Lecture Notes in Computer Science, Vol. 242, pp 21-70. Springer-Verlag, 1986.   
[Clac24]: Christopher D. Clack. Research https://christopherclack.com/research/research-topics   
[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   
[CMUCL]: CMUCL: Project history & who's who (2020) https://cmucl.org/credits.html   
[Cous87]: Cousineau, Guy, P-L. Curien, and Michel Mauny. "The categorical abstract machine." Science of computer programming 8, no. 2 (1987): 173-202.   
[Cous90]: Cousineau, Guy, and Gérard Huet. "The CAML primer." Version 2.6.1, INRIA, 1990.   
[Danc87]: Gill Dancey, INFORMATICS DIVISION NEWSLETTER No. 10 May 1987 https://www.chilton-computing.org.uk/inf/pdfs/inf_newsletters.pdf   
[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.   
[Dett86]: Dettmer, Roger. “Flagship. A fifth-generation machine.” Electronics and Power 32 (1986): 203-208.   
[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   
[Duce86]: D. A. Duce, Software Engineering Research at RAL, 13 February 1986 https://www.chilton-computing.org.uk/inf/pdfs/seg/seg101.pdf   
[Fate2003]: Souza, Paulo Ney de, Richard J. Fateman, Joel Moses and Clifford W Yapp. “The Maxima Book.” (2003). https://maxima.sourceforge.io/docs/maximabook/maximabook-19-Sept-2004.pdf   
[Faul84]: Faulkner, T. L., & Pavelin, C. J. (1984). Atlas 10 computer. ICL technical journal, 4, 13-32.   
[Feig83]: Feigenbaum, Edward A.; McCorduck, Pamela (1983). The fifth generation: artificial intelligence and Japan's computer challenge to the world. Reading, Mass: Addison-Wesley. ISBN 978-0-201-11519-2.   
[Fiel88]: Anthony J. Field, Peter Harrison - Functional Programming, 1988   
[Franz]: History of Franz Inc. https://franz.com/about/company.history.lhtml   
[GEC63]: GEC Series 63 https://www.chilton-computing.org.uk/inf/alvey/p003.htm   
[Gord82]: Mike Gordon, Larry Paulson, 1982-11-03 in Polymorphism Vol 1 part 1 Jan 83   
[Gord2000]: Gordon M. From LCF to HOL: a short history. In Proof, language, and interaction 2000 Jul 24 (pp. 169-186).   
[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   
[Harp85]: Robert Harper, Report on the Standard ML Meeting, Edinburgh, May 23-25, 1985. https://smlfamily.github.io/history/Harper-SML-meeting-1985_05.pdf   
[Harr87]: Harrison, P.G., Reeve, M.J. (1987). The parallel graph reduction machine, ALICE. In: Fasel, J.H., Keller, R.M. (eds) Graph Reduction. GR 1986. Lecture Notes in Computer Science, vol 279. Springer, Berlin, Heidelberg. doi:10.1007/3-540-18420-1_55   
[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   
[HOL88]: HOL88 https://github.com/theoremprover-museum/HOL88   
[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   
[Huet15]: Gérard Huet, Thierry Coquand and Christine Paulin. Early history of Coq, September 2015 https://coq.inria.fr/refman/history.html    
[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   
[John85]: Johnsson, T. (1985). Lambda lifting: Transforming programs to recursive equations. In: Jouannaud, JP. (eds) Functional Programming Languages and Computer Architecture. FPCA 1985. Lecture Notes in Computer Science, vol 201. Springer, Berlin, Heidelberg. doi:10.1007/3-540-15975-4_37   
[John86]: Johnsson, T. (1987). Target code generation from G-machine code. In: Fasel, J.H., Keller, R.M. (eds) Graph Reduction. GR 1986. Lecture Notes in Computer Science, vol 279. Springer, Berlin, Heidelberg. doi:10.1007/3-540-18420-1_53   
[John87]: Johnsson, Thomas. "Compiling Lazy Functional Language." PhD Thesis, Chalmers University of Technology (1987).   
[Kean94]: Keane J. A. An overview of the Flagship system. Journal of Functional Programming. 1994;4(1):19-45. doi:10.1017/S0956796800000927   
[Kess86]: R. R. Kessler, J. C. Peterson, H. Carr, G. P. Duggan, and J. Knell. 1986. EPIC - a retargetable, highly optimizing Lisp compiler. In Proceedings of the 1986 SIGPLAN symposium on Compiler construction (SIGPLAN '86). Association for Computing Machinery, New York, NY, USA, 118–130. doi:10.1145/12276.13323   
[MacL15]: Rob MacLachlan, History of the CMUCL Project (2015) https://www.cons.org/cmucl/doc/cmucl-history.html   
[MacQ85]: David MacQueen and Robin Milner. 1985. Record of the Standard ML Meeting, Edinburgh, 6–8 June 1984. Polymorphism: The ML/LCF/Hope Newsletter II, 1 (Jan.), 16. http://lucacardelli.name/Papers/Polymorphism%20Vol%20II,%20No%201.pdf   
[MacQ14]: Luca Cardelli and the Early Evolution of ML, by David MacQueen. A paper presented at the Luca Cardelli Fest at Microsoft Research Cambridge on Sept. 8, 2014.   
[MacQ15]: MacQueen, David B. The History of Standard ML: Ideas, Principles, Culture https://www.youtube.com/watch?v=NVEgyJCTee4   
[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   
[MacQ22]: D. MacQueen, A New Match Compiler for Standard ML of New Jersey https://icfp22.sigplan.org/details/mlfamilyworkshop-2022-papers/3/A-New-Match-Compiler-for-Standard-ML-of-New-Jersey    
[Matt88]: Matthews D.C.J. (1988) An Overview of the Poly Programming Language. In: Atkinson M.P., Buneman P., Morrison R. (eds) Data Types and Persistence. Topics in Information Systems. Springer, Berlin, Heidelberg. doi:10.1007/978-3-642-61556-6_4    
[Matt89]: Matthews, David CJ. Papers on Poly/ML. No. UCAM-CL-TR-161. University of Cambridge, Computer Laboratory, 1989.   
[Matt2000]: David Matthews, History and Acknowledgements https://polyml.org/FAQ.html#history   
[Maun86]: Mauny, M., & Suárez, A. (1986). Implementing functional languages in the Categorical Abstract Machine. Proceedings of the 1986 ACM Conference on LISP and Functional Programming - LFP ’86. doi:10.1145/319838.319869   
[Maun88]: Michel Mauny, A new functional language: CAML Release 2.5 in comp.lang.misc, 05/09/88   
[McDo89]: D. McDonald, editor. CMU Common Lisp User's Manual: Mach/IBM RT PC edition. Carnegie Mellon University. CMU-CS-89-132, April 1989. https://doi.org/10.1184/R1/6604121.v1   
[McJo24]: Paul McJones, John Allen (1937-2022) and Anatomy of LISP https://mcjones.org/dustydecks/archives/2024/04/11/1249/    
[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   
[Miln83b]: Robin Milner. 1983. A Proposal for Standard ML (second draft). June 1983. 50 pages. http://sml-family.org/history/SML-proposal-6-83.pdf   
[Miln83c]: A Proposal for Standard ML, by Robin Milner, November 1983. The third draft of Milner's proposal for core Standard ML. https://smlfamily.github.io/history/SML-proposal-11-83.pdf   
[Miln84]: Robin Milner, The Standard ML Core Language, July 1984. https://smlfamily.github.io/history/SML-proposal-7-84.pdf   
[Miln84b]: Robin Milner. 1984. A proposal for standard ML. In Proceedings of the 1984 ACM Symposium on LISP and functional programming (LFP '84). Association for Computing Machinery, New York, NY, USA, 184–197. doi:10.1145/800055.802035   
[Miln84c]: Robin Milner, The Standard ML Core Language, October, 1984. The second draft of the "Core Language" design. https://smlfamily.github.io/history/SML-proposal-10-84.pdf   
[Miln85]: Robin Milner, The Standard ML Core Language (Revised), September, 1985. The third draft of the "Core Language" design. https://smlfamily.github.io/history/SML-proposal-9-85.pdf   
[Miln88]: Harper, R.M., Milner, R., Tofte, M., The Definition of Standard ML, Version 2 Report ECS-LFCS-88-62, Laboratory for Foundations of Computer Science, Computer Science Department, Edinburgh University, 1988.   
[Mitc84]: John C. Mitchell. 1984. Coercion and type inference. In Proceedings of the 11th ACM SIGACT-SIGPLAN symposium on Principles of programming languages (POPL '84). Association for Computing Machinery, New York, NY, USA, 175–185. https://doi.org/10.1145/800017.800529   
[MLKit2002]: About the ML Kit https://web.archive.org/web/20020827144153/http://www.itu.dk/research/mlkit/about.html   
[Moss89]: A. E. Mossberg, Edinburgh ML (summary) comp.lang.misc, Dec 18, 1989   
[Mosses]: Peter Mosses, Affiliations https://pdmosses.github.io/affiliations/   
[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   
[Neum90]: Pierre-Louis Neumann, New Caml version in comp.lang.misc, 03/29/90   
[Nuprl94]: Nuprl 3.2 (26-MAY-94) https://github.com/owo-lang/nuprl-3 https://web.archive.org/web/20220630143027/http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/areas/reasonng/atp/systems/nuprl/0.html   
[Odag97]: Odagiri, H., Nakamura, Y., & Shibuya, M. (1997). Research consortia as a vehicle for basic research: The case of a fifth generation computer project in Japan. Research Policy, 26(2), 191–207. doi:10.1016/s0048-7333(97)00008-5   
[Oakl90]: Brian Oakley and Kenneth Owen. 1990. Alvey: Britain's strategic computing initiative. MIT Press, Cambridge, MA, USA.   
[Paul96]: Paulson, Lawrence Charles. “ML for the working programmer (2. ed.).” (1996).   
[Paul22b]: Lawrence Paulson. Memories: Edinburgh ML to Standard ML https://lawrencecpaulson.github.io/2022/10/05/Standard_ML.html   
[PERQ1]: PERQ History, 1.3. EARLY DAYS http://www.chilton-computing.org.uk/acd/sus/perq_history/part_1/c3.htm   
[Phil99]: Phillips, Eve Marie. "If it works, it's not AI: a commercial look at artificial intelligence startups." PhD diss., Massachusetts Institute of Technology, 1999.   
[POP19]: INFORMATION ABOUT POPLOG AND POP-11 2019 https://poplogarchive.getpoplog.org/poplog.info.html   
[POPLOG]: Poplog https://github.com/poplog/poplog   
[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   
[RAL87]: Informatics Annual Report 1986-87 http://www.chilton-computing.org.uk/inf/literature/inf_annual_reports/p003.htm    
[RAL89]: Informatics Annual Report 1988-9 http://www.chilton-computing.org.uk/inf/literature/inf_reports/p005.htm   
[Rash89]: Rashid, Richard, Robert Baron, Alessandro Forin, David Golub, Michael Jones, Douglas Orr, and Richard Sanzi. "Mach: a foundation for open systems (operating systems)." In Proceedings of the Second Workshop on Workstation Operating Systems, pp. 109-113. IEEE, 1989.   
[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).   
[Schmidt]: CV https://people.cs.ksu.edu/~schmidt/vita.html   
[Shap83]: Ehud Y. Shapiro. 1983. The fifth generation project — a trip report. Commun. ACM 26, 9 (Sept. 1983), 637–641. doi:10.1145/358172.358179   
[Slom89]: Sloman, Aaron. "The Evolution of Poplog and Pop-11 at Sussex University." POP-11 Comes of Age: The Advancement of an AI Programming Language (1989): 30-54.   
[Sokolowski]: CV https://prabook.com/web/stefan_andrzej.sokolowski/90807   
[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   
[SPJ87]: Peyton Jones, Simon L. The implementation of functional programming languages (prentice-hall international series in computer science). Prentice-Hall, Inc., 1987.   
[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   
[Stee84]: Steele, Guy L. "Common LISP. The language." Bedford: Digital Press (1984).   
[Stee96]: Guy L. Steele and Richard P. Gabriel. 1996. The evolution of Lisp. Uncut draft.   
[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   
[Witt85]: R. W. Witty, SEG ANNUAL REPORT September 84-September 85, 30 September 1985 https://www.chilton-computing.org.uk/inf/pdfs/seg/seg74.pdf   
[Wolf89]: David Wolfram, ACE Version 1.3 Distribution comp.lang.misc, Jun 20, 1989   
[Yuas85]: Yuasa, Taiichi, and Masami Hagiya. "Kyoto Common Lisp Report." Research Institute for Mathematical Sciences, Kyoto University (1985.11.13).   
