start 1-to-1 translation
This commit is contained in:
parent
a2ee293144
commit
62e2eb051a
7 changed files with 10598 additions and 383 deletions
665
prehist.md
665
prehist.md
|
|
@ -1,36 +1,36 @@
|
|||
История применения и оценки функционального программирования
|
||||
History of the Use and Evaluation of Functional Programming
|
||||
=======
|
||||
|
||||
- [История применения и оценки функционального программирования](#история-применения-и-оценки-функционального-программирования)
|
||||
- [Часть 0: что было, когда функционального программирования не было.](#часть-0-что-было-когда-функционального-программирования-не-было)
|
||||
- [Когда _чего_ не было?](#когда-чего-не-было)
|
||||
- [Для чего нужна эта работа и в чем ее отличия от других](#для-чего-нужна-эта-работа-и-в-чем-ее-отличия-от-других)
|
||||
- [Лямбда-криптозой](#лямбда-криптозой)
|
||||
- [Лямбда-фанерозой](#лямбда-фанерозой)
|
||||
- [Ветвь обоих Кембриджей](#ветвь-обоих-кембриджей)
|
||||
- [В Кембридже](#в-кембридже)
|
||||
- [History of the Use and Evaluation of Functional Programming](#history-of-the-use-and-evaluation-of-functional-programming)
|
||||
- [Part 0: What existed when functional programming did not.](#part-0-what-existed-when-functional-programming-did-not)
|
||||
- [When was _what_ not there?](#when-was-what-not-there)
|
||||
- [Why this work is needed and how it differs from others](#why-this-work-is-needed-and-how-it-differs-from-others)
|
||||
- [Lambda Cryptozoic](#lambda-cryptozoic)
|
||||
- [Lambda Phanerozoic](#lambda-phanerozoic)
|
||||
- [The Branch of Both Cambridges](#the-branch-of-both-cambridges)
|
||||
- [In Cambridge](#in-cambridge)
|
||||
- [CPL](#cpl)
|
||||
- [псевдоCPL](#псевдоcpl)
|
||||
- [Следующие 700 непопулярных языков](#следующие-700-непопулярных-языков)
|
||||
- [Следующие 700 исписанных листов](#следующие-700-исписанных-листов)
|
||||
- [Следующие 700 вариаций семи фич](#следующие-700-вариаций-семи-фич)
|
||||
- [больше не фичи](#больше-не-фичи)
|
||||
- [отсутствие лямбд](#отсутствие-лямбд)
|
||||
- [выражение `where`](#выражение-where)
|
||||
- [тернарный оператор ветвления](#тернарный-оператор-ветвления)
|
||||
- [пока еще фичи](#пока-еще-фичи)
|
||||
- [конструкция `let`](#конструкция-let)
|
||||
- [аннотация рекурсии](#аннотация-рекурсии)
|
||||
- [отсутствие аннотаций рекурсии](#отсутствие-аннотаций-рекурсии)
|
||||
- [отсутствие аннотаций типов](#отсутствие-аннотаций-типов)
|
||||
- [обозначение блоков отступами](#обозначение-блоков-отступами)
|
||||
- ["одновременные"/"параллельные" декларации](#одновременныепараллельные-декларации)
|
||||
- [обсуждавшиеся фичи](#обсуждавшиеся-фичи)
|
||||
- [параметрический полиморфизм](#параметрический-полиморфизм)
|
||||
- [Изобрел ли Ландин АлгТД?](#изобрел-ли-ландин-алгтд)
|
||||
- [Следующие 700 не самых быстрых имплементаций](#следующие-700-не-самых-быстрых-имплементаций)
|
||||
- [В другом Кембридже](#в-другом-кембридже)
|
||||
- [Мартин Ричардс](#мартин-ричардс)
|
||||
- [pseudoCPL](#pseudocpl)
|
||||
- [The Next 700 Unpopular Languages](#the-next-700-unpopular-languages)
|
||||
- [The Next 700 Written Pages](#the-next-700-written-pages)
|
||||
- [The Next 700 Variations of Seven Features](#the-next-700-variations-of-seven-features)
|
||||
- [No Longer Features](#no-longer-features)
|
||||
- [Absence of Lambdas](#absence-of-lambdas)
|
||||
- [`where` expression](#where-expression)
|
||||
- [ternary branching operator](#ternary-branching-operator)
|
||||
- [Still Features](#still-features)
|
||||
- [`let` construct](#let-construct)
|
||||
- [recursion annotation](#recursion-annotation)
|
||||
- [absence of recursion annotations](#absence-of-recursion-annotations)
|
||||
- [absence of type annotations](#absence-of-type-annotations)
|
||||
- [block delimiting by indentation](#block-delimiting-by-indentation)
|
||||
- ["simultaneous"/"parallel" declarations](#simultaneousparallel-declarations)
|
||||
- [Discussed Features](#discussed-features)
|
||||
- [Parametric Polymorphism](#parametric-polymorphism)
|
||||
- [Did Landin Invent ADTs?](#did-landin-invent-adts)
|
||||
- [The Next 700 Not-So-Fast Implementations](#the-next-700-not-so-fast-implementations)
|
||||
- [In the Other Cambridge](#in-the-other-cambridge)
|
||||
- [Martin Richards](#martin-richards)
|
||||
- [BCPL](#bcpl)
|
||||
- [PAL](#pal)
|
||||
- [McG](#mcg)
|
||||
|
|
@ -179,155 +179,154 @@
|
|||
- [Литература](#литература)
|
||||
|
||||
|
||||
Часть 0: что было, когда функционального программирования не было.
|
||||
Part 0: What existed when functional programming did not.
|
||||
===================================
|
||||
|
||||
Когда _чего_ не было?
|
||||
When was _what_ not there?
|
||||
-------------------
|
||||
|
||||
> Функциональное программирование - это инженерная ветвь конструктивной математики.
|
||||
Олег Нижников.
|
||||
> Functional programming is an engineering branch of constructive mathematics.
|
||||
Oleg Nizhnikov.
|
||||
|
||||
|
||||
Мы не ставим перед собой цели дать определение функциональному программированию. Мы, однако же, вынуждены определить какие-то практические рамки для нашего исследования. Выбрать историю _чего именно_ мы пишем, и выбрать что-то обозримое.
|
||||
И многие определения ФП просто непрактичны с этой точки зрения. История языков с первоклассными функциями в наши дни фактически равна истории языков программирования, ведь даже редкие языки в которых их до сих пор нет - вроде C++ или Rust - обычно связаны разными историческими отношениями с языками где первоклассные функции есть.
|
||||
Не годится также и не такая необъятная, но все еще неподъемная группа языков "по каким-то историческим причинам считающиеся функциональными", о которых обычно и пишут те, кто пишут историю ФП. Главная причина того, почему это определения ФЯ для нас не годится - в этой группе языков есть Лисп, и мы не хотим писать историю Лиспа. В основном потому, что история Лиспа слишком громадная тема, чтоб рядом с ней было вообще можно заметить историю прочих языков этой "традиционной" группы. Мало того, сейчас есть проблема, которой во времена выбора "исторически сложившегося перечня ФЯ" просто не было: сегодня Лисп - типичный представитель огромной категории языков. Так же как и в какую-нибудь Java, первоклассные функции были добавлены в Лисп после того, как он уже долгое время существовал и это не такая уж значительная и важная деталь истории языка. И написание истории функционализации Лиспа потребовало бы сравнения с другими языками, прошедшими через тот же процесс. А именно почти со всеми существующими сейчас языками программирования.
|
||||
Мы бы хотели поставить перед собой реальную цель и ограничиться функциональными языками в более узком смысле, историю которых мы рассмотрим немного более глубоко, чем можно позволить себе рассмотреть историю всех языков.
|
||||
Чтоб сузить группу языков мы добавим к первой фиче
|
||||
We do not aim to define functional programming. However, we are forced to set some practical boundaries for our study: to choose the history of _what exactly_ we are writing, and to choose something manageable.
|
||||
And many definitions of FP are simply impractical from this point of view. The history of languages with first-class functions today is effectively the history of programming languages, because even the rare languages that still do not have them, such as C++ or Rust, are usually tied by various historical relationships to languages that do.
|
||||
The group of languages "considered functional for some historical reasons" is also unsuitable, even though it is not so vast, because it is still unmanageable. These are the languages that people usually write about when they write the history of FP. The main reason this definition of functional languages does not work for us is that this group includes Lisp, and we do not want to write the history of Lisp. Mainly because the history of Lisp is a topic so huge that next to it you would hardly notice the history of other languages in this "traditional" group at all. Moreover, there is now a problem that did not exist when the "historically formed list of functional languages" was chosen: today Lisp is a typical representative of a huge category of languages. Just like in, say, Java, first-class functions were added to Lisp after it had already existed for a long time, and this is not such a significant or important detail in the language's history. Writing the history of Lisp's functionalization would require comparisons with other languages that went through the same process, namely almost all programming languages that exist today.
|
||||
We would like to set ourselves a realistic goal and limit ourselves to functional languages in a narrower sense, whose history we will consider a bit more deeply than one can afford when looking at the history of all languages.
|
||||
To narrow the group of languages, we will add some features to the first one:
|
||||
|
||||
* Первоклассные функции
|
||||
* First-class functions
|
||||
|
||||
еще какие-нибудь.
|
||||
and a few more.
|
||||
|
||||
* Параметрический полиморфизм и вывод/реконструкция типов
|
||||
* Parametric polymorphism and type inference/reconstruction
|
||||
|
||||
позволяют существенно сократить предмет исследования, но все еще недостаточно. Так что мы добавим
|
||||
reduce the subject significantly, but still not enough. So we will add
|
||||
|
||||
* Алгебраические типы и паттерн-матчинг
|
||||
* Algebraic data types and pattern matching
|
||||
|
||||
Вот эта последняя фича, наконец-то, дает нам семейство языков подходящего размера.
|
||||
К сожалению, объединение фич выглядит довольно произвольным. Кроме того, если когда-нибудь АлгТД и ПМ станут так же распространены как первоклассные функции (мы бы не стали на это особо рассчитывать), проблема истории всех языков вернется, чтоб преследовать наших последователей, если они у нас, конечно, будут.
|
||||
This last feature finally gives us a family of languages of a suitable size.
|
||||
Unfortunately, this bundle of features looks rather arbitrary. Moreover, if algebraic data types and pattern matching ever become as widespread as first-class functions (we would not count on it), the problem of the history of all languages will return to haunt our successors, if we have any.
|
||||
|
||||
Языки с этим набором фич, бывает, называются "Эмелеподобными языками".
|
||||
Только вот люди не достаточно часто соглашаются какие языки ML-подобны. Не все ML-и так уж подобны другим ML-ям, а что уж говорить про не ML-и.
|
||||
Languages with this set of features are sometimes called "ML-like languages."
|
||||
Only people do not often agree on which languages are ML-like. Not all MLs are that similar to other MLs, let alone non-MLs.
|
||||
|
||||
Попробуем найти первый язык с такими фичами и определить семейство через него.
|
||||
Хорошие новости: существует один такой язык - Hope, никто, насколько нам известно, не изобретал еще раз такое же сочетание независимо. Он получился из "слияния" языков, в каждом из которых был неполный набор интересных нам фич.
|
||||
Let us try to find the first language with these features and define the family through it.
|
||||
The good news: there is one such language, Hope; as far as we know, no one independently invented the same combination again. It resulted from a "merging" of languages, each of which had an incomplete set of the features we care about.
|
||||
|
||||
Плохие новости: не все языки, историю которых мы хотели бы писать, происходят от этого языка, так что наши надежды на "Hope-образные языки" не оправдались так же, и по тем же причинам, что и на "ML-образные". "Слияние", вероятно, не самая подходящая перспектива в этом случае. Отношения между языками не хотят принимать вид удобных деревьев или графов.
|
||||
The bad news: not all languages whose history we would like to write derive from that language, so our hopes for "Hope-like languages" did not come true for the same reasons that our hopes for "ML-like languages" did. "Merging" is probably not the best perspective here. Relationships between languages do not want to take the shape of convenient trees or graphs.
|
||||
|
||||
Правильнее будет говорить про набор языков, каждый из которых, развиваясь, позаимствовал недостающие до нашего определяющего наборы фичи из остальных, а Hope - просто первый результат этого процесса, который мы будем далее называть "хопизацией". ML как единый язык этот процесс не проходил, его прошли по отдельности по крайней мере три языка с "ML" в названии.
|
||||
It is more accurate to speak about a set of languages, each of which, in its development, borrowed the missing pieces of our defining feature set from the others, and Hope is simply the first result of this process, which we will later call "hopization." ML as a single language did not go through this process; at least three languages with "ML" in their name did so separately.
|
||||
|
||||
В те времена такое взаимодействие языков, проектов и их авторов было бы затруднено, если бы участники находились далеко друг от друга. Они и не находились далеко. Исследовательская программа, историю которой мы будем писать, начиналась в Эдинбурге и соседнем с ним городе Сент-Эндрюсе, так что мы, наконец-то, нашли рамки которые нам подходят, пусть и географические, что, конечно, не лучший вариант, но что есть - то есть.
|
||||
At that time, such interaction of languages, projects, and their authors would have been difficult if the participants had been far apart. They were not. The research program whose history we will write began in Edinburgh and the neighboring town of St Andrews, so we finally found boundaries that suit us, even if they are geographic, which is not the best option, but it is what it is.
|
||||
|
||||
Почти все языки, происходящие от первоначальной группы языков Эдинбургской программы, сохранили обсуждаемые свойства, а если мы сделаем еще шаг назад и рассмотрим то, от чего они произошли - назовем эту, предыдущую программу "ветвью обоих Кембриджей", то такой однородности всех происходящих от нее языков не будет.
|
||||
Almost all languages derived from the initial group of the Edinburgh program kept the properties under discussion, but if we step back once more and look at what they came from - let us call that earlier program the "branch of both Cambridges" - then such uniformity among all of its descendants will not hold.
|
||||
|
||||
Мы пишем историю "Эдинбургской исследовательской программы". Но это звучит длинновато, так что далее мы обычно будем называть группу языков, которую мы выбрали для написания истории функционального программирования, просто "функциональные языки", как делали и наши великие предшественники. В этом смысле наша работа ничем не отличается от других работ по истории функционального программирования.
|
||||
А в чем отличается?
|
||||
We are writing the history of the "Edinburgh research program." But that sounds a bit long, so from now on we will usually call the group of languages we chose to write the history of functional programming simply "functional languages," as our great predecessors did. In this sense our work is no different from other works on the history of functional programming.
|
||||
And how does it differ?
|
||||
|
||||
Для чего нужна эта работа и в чем ее отличия от других
|
||||
Why this work is needed and how it differs from others
|
||||
-----------
|
||||
|
||||
> История развития теории типов, которая в последствии привела к системе типов Standard ML, насчитывает более ста лет.
|
||||
> Д. МакКвин, Р. Харпер, Дж. Реппи, История Standard ML [MacQ20]
|
||||
> The history of the development of type theory, which later led to the Standard ML type system, spans more than a hundred years.
|
||||
> D. MacQueen, R. Harper, J. Reppy, History of Standard ML [MacQ20]
|
||||
|
||||
|
||||
Не то чтобы литературы по истории ФП было мало. Уже существуют как обзорные материалы по ФП вообще [Huda89] [Turn12], так и истории отдельных языков или их семейств [Hud07] [MacQ20], биографии исследователей [Camp85] [MacQ14]. Зачем нужна еще одна?
|
||||
It is not that there is little literature on the history of FP. There are already survey materials on FP in general [Huda89] [Turn12], histories of individual languages or families [Hud07] [MacQ20], and biographies of researchers [Camp85] [MacQ14]. Why do we need another one?
|
||||
|
||||
### Лямбда-криптозой
|
||||
### Lambda Cryptozoic
|
||||
|
||||
Когда, в очередной раз, не хватает десятков гигабайт памяти для компиляции кода на Хаскеле, естественным образом возникает вопрос: в каком же _смысле_ функциональное программирование существовало в каком-нибудь 1973-ем году? К сожалению, материалы по истории ФП обычно не уделяют этому особого внимания. Для историй функционального программирования в них часто слишком мало истории программирования.
|
||||
Мы не ставим перед собой цели дать определение "программированию", но в этой работе предполагаем, что это процесс написания программ. И наши великие предшественники, в своих работах по истории функционального программирования, не особенно любят писать какого размера программы получались в результате этого процесса.
|
||||
Более того, часто историк программирования уходит в такие глубины прошлого, про существование программирования в которых можно говорить только с большой натяжкой. Например, предыстория Standard ML начинается аж с 1874 года [MacQ20].
|
||||
Понятно, что в 1874 функционального программирования не было, но было ли оно, например, в 1974-ом? Какие программы к этому году были написаны на функциональных языках? Какие имплементации были доступны и для кого? До какого года ФЯ могло существовать только так же, как могло и в 1874-ом году: как нотация в книгах, тетрадях, на досках и так далее?
|
||||
Например, часто утверждается, что ML появился в 1973 году, но что именно произошло в этом году? Упрощенно говоря, в этом году у Робина Милнера появилось желание писать интерактивный решатель теорем не на Лиспе. И в нашей работе мы покажем в каком году Милнер написал часть интерактивного решателя теорем на ML. Какая это была часть, сколько в ней было строк кода. Кто и через сколько лет написал интерактивный решатель теорем полностью на ML. И кто и когда написал интерактивный решатель теорем полностью на ML, имплементация которого, в свою очередь, и сама написана на ML. И сколько строк кода было в этой имплементации.
|
||||
Между мечтой и возможностью большая разница и существенный временной интервал и мы считаем, что такая перспектива может быть полезной, если кто-то не согласен, что история чего-то начинается с мечты, и на ней же и заканчивается, ведь имплементация идеи тривиальна и не интересна.
|
||||
Нельзя сказать, что вопрос применимости имплементаций ФЯ для программирования вовсе не поднимается, но он не особенно интересен нашим великим предшественникам. В некоторых обзорах перечисляют имплементации, которые авторы (обзора, но нередко автор обзора является и автором одной из этих имплементаций) считают "неигрушечными", "эффективными" [Huda89], "быстрыми" [SPJ87], но критерии не сформулированы четко, и вполне возможно, что у вас бы сложилось другое впечатление, если б вы узнали об этих имплементациях больше. У нас определенно сложилось другое впечатление. В таких списках через запятую перечислены компиляторы, которые компилировали себя и другие проекты в десятки тысяч строк вместе с компиляторами, которые этого не делали.
|
||||
Поэтому мы постараемся установить, какого размера программы писали с помощью имплементаций ФЯ, какая была производительность у этих программ.
|
||||
When, once again, tens of gigabytes of memory are not enough to compile Haskell code, a natural question arises: in what _sense_ did functional programming exist in, say, 1973? Unfortunately, materials on the history of FP usually pay little attention to this. In histories of functional programming there is often too little history of programming.
|
||||
We do not aim to define "programming," but in this work we assume it is the process of writing programs. And our great predecessors, in their works on the history of functional programming, do not especially like to write about what size programs resulted from this process.
|
||||
Moreover, the historian of programming often goes so deep into the past that one can speak of the existence of programming there only with great stretch. For example, the prehistory of Standard ML begins as far back as 1874 [MacQ20].
|
||||
Clearly, there was no functional programming in 1874, but was there, for example, in 1974? What programs had been written in functional languages by that year? What implementations were available and to whom? Until what year could functional languages exist only in the same way they could in 1874: as notation in books, notebooks, on blackboards, and so on?
|
||||
For example, it is often claimed that ML appeared in 1973, but what exactly happened that year? Roughly speaking, in that year Robin Milner wanted to write an interactive theorem prover not in Lisp. And in our work we will show in which year Milner wrote a part of the interactive theorem prover in ML. What part it was, how many lines of code it contained. Who and how many years later wrote an interactive theorem prover entirely in ML. And who and when wrote an interactive theorem prover entirely in ML whose implementation, in turn, is itself written in ML. And how many lines of code were in that implementation.
|
||||
Between a dream and a possibility there is a big difference and a significant time interval, and we believe such a perspective can be useful if someone does not agree that the history of something begins with a dream and ends with it, since implementing the idea is trivial and uninteresting.
|
||||
It cannot be said that the question of the applicability of functional-language implementations for programming is not raised at all, but it is not very interesting to our great predecessors. In some surveys they list implementations that the authors (of the survey, and often the author of the survey is also an author of one of these implementations) consider "non-toy," "efficient" [Huda89], "fast" [SPJ87], but the criteria are not clearly formulated, and it is quite possible you would have a different impression if you learned more about these implementations. We certainly did. Such lists lump together compilers that compiled themselves and other projects of tens of thousands of lines with compilers that did not.
|
||||
Therefore we will try to determine what size programs were written with functional-language implementations and what performance those programs had.
|
||||
|
||||
Если что-то может помешать историку ФП все больше и больше углубляться в прошлое - то это название. Некоторые авторы так любят какое-то название, что продолжают использовать его для все новых и все менее схожих вещей. Синтаксисы многих функциональных языков в 80-х более похожи друг на друга, чем на свои версии с теми же названиями из 70-х. К счастью, первый раз назвали что-то ML очень давно, и нет препятствий для того чтоб начать историю ML с начала, или даже задолго до его начала.
|
||||
К сожалению, многие любят называть одно и то же по-разному. Да, первый компилятор Хаскеля был получен всего за пару месяцев из компилятора Нехаскеля, что явно указывает на то, что уже была проделана большая работа, которую вполне обоснованно можно считать работой по созданию Хаскеля. Три из пяти первых компиляторов Хаскеля разрабатывались долгие годы до того, как появилась сама идея спроектировать этот язык. Увы, Нехаскель не назывался "Хаскель", так что ничего не поделаешь - в истории Хаскеля [Hud07] уделить этому больше нескольких строк нельзя. Да, авторы Хаскеля выбрали другой Нехаскель как основу для первого Хаскель-репорта. И этот Нехаскель похож на Хаскель 1.0 больше чем ML в 82-ом на ML в 84-ом. Извините, название было не "Хаскель" - наши великие предшественники не могут писать историю этого.
|
||||
If anything can prevent the historian of FP from going deeper and deeper into the past, it is the name. Some authors love a name so much that they keep using it for newer and less similar things. The syntaxes of many functional languages in the 1980s are more similar to each other than to their own versions with the same names from the 1970s. Luckily, the first time something was called ML was very long ago, and there are no obstacles to starting the history of ML from the beginning, or even long before its beginning.
|
||||
Unfortunately, many people like to call the same thing by different names. Yes, the first Haskell compiler was obtained in just a couple of months from a Nehaskell compiler, which clearly indicates that a great deal of work had already been done, which can reasonably be considered work on creating Haskell. Three of the first five Haskell compilers were developed for many years before the very idea of designing this language appeared. Alas, Nehaskell was not called "Haskell," so there is nothing to be done - in the history of Haskell [Hud07] it is impossible to devote more than a few lines to this. Yes, the authors of Haskell chose another Nehaskell as the basis for the first Haskell Report. And that Nehaskell resembles Haskell 1.0 more than ML in 1982 resembles ML in 1984. Sorry, the name was not "Haskell" - our great predecessors cannot write its history.
|
||||
|
||||
Все это, в основном, последствия того, что наши великие предшественники писали в первую очередь истории идей. И они делали это не потому, что это легко. Одна из причин того, что мы не собираемся писать историю идей - проследить историю идей очень сложно. Так что мы пишем историю имплементаций в первую очередь, и только потом историю идей.
|
||||
Для каждой идеи можно найти ту, от которой она произошла, и каждая тащит все дальше в глубины веков, там идеи до самого низа. Так историк функционального программирования и оказывается в 1874-ом году. История имплементаций легко решает эту проблему (решает даже слишком хорошо, но об этом позднее).
|
||||
Идеи оставляют меньше следов, и следов менее удобных для историка. Имплементация оставляет после себя разные версии кода, отметки в нем, репорты, анонсы и описания релизов, из которых понятно что заработало и когда.
|
||||
Идея оставляет после себя статью, которая может быть опубликована через годы и "приведена в порядок" каким-то стирающим историю способом. Что это значит? Обзор родственных работ в статьях документирует отношение идей, но не их историю. Влияние одних идей на другие может декларироваться, но на самом деле "повлиявшая" идея может быть обнаружена только после того, как идея на которую она "повлияла" была переоткрыта самостоятельно.
|
||||
Бывает, что автор прямо говорит об этом. Например Ксавье Леруа пишет что переизобрел некоторые идеи из машины Кривина не зная о ней и добавил ссылки только после того, как другие люди обратили его внимание на сходство. Часть идей по имплементации Chez Scheme ее автор открыл самостоятельно, а потом только обнаружил их в VAX ML, а часть действительно позаимствовал. Но не все считают нужным сообщить об этом. Хуже того, такие свидетельства могут противоречить другим. Например, мнение авторов языка о том, на какие языки они повлияли может не совпадать с мнением авторов этих языков о том, какие языки повлияли на них.
|
||||
Тут нет ничего удивительного, идеи о том, как делать языки программирования, нередко возникают независимо. Даже алгоритм Хиндли-Милнера - нетривиальная и точно специфицируемая идея - был независимо переизобретен, но никто не написал независимо два одинаковых компилятора.
|
||||
Дополнительная сложность тут в том, что добавлять ссылки на статьи сильно легче, чем использовать код компиляторов, так что в графе получается слишком много ребер, если мы пишем историю идей.
|
||||
Для объединения имплементаций в семейства мы будем использовать более редкие и надежно устанавливаемые отношения: общий код, общие авторы, использование одной для бутстрапа другой.
|
||||
All of this is mostly a consequence of our great predecessors writing primarily histories of ideas. And they did so not because it is easy. One of the reasons we are not going to write a history of ideas is that tracing the history of ideas is very difficult. So we write a history of implementations first, and only then a history of ideas.
|
||||
For each idea you can find the one it came from, and each one drags you further into the depths of the centuries, where there are ideas all the way down. That is how the historian of functional programming ends up in the year 1874. The history of implementations easily solves this problem (even too well, but more on that later).
|
||||
Ideas leave fewer traces, and traces that are less convenient for the historian. An implementation leaves different versions of code, marks in it, reports, announcements, and release descriptions from which it is clear what worked and when.
|
||||
An idea leaves an article that may be published years later and "cleaned up" in some history-erasing way. What does this mean? A related-work review in articles documents relationships among ideas, but not their history. The influence of one idea on another may be declared, but in fact the "influencing" idea may only be discovered after the idea it "influenced" was rediscovered independently.
|
||||
Sometimes the author says this directly. For example, Xavier Leroy writes that he reinvented some ideas from the Krivine machine without knowing about it and added references only after other people drew his attention to the similarity. Some ideas in the implementation of Chez Scheme were discovered independently by its author and only later found in VAX ML, and some were actually borrowed. But not everyone feels the need to report this. Worse, such testimony can contradict others. For example, the authors' view of which languages they influenced may not coincide with the view of the authors of those languages about which languages influenced them.
|
||||
There is nothing surprising here: ideas about how to make programming languages often arise independently. Even the Hindley-Milner algorithm - a nontrivial and precisely specifiable idea - was independently reinvented, but no one independently wrote two identical compilers.
|
||||
An additional difficulty here is that adding references to articles is much easier than using compiler code, so the graph ends up with too many edges if we write a history of ideas.
|
||||
To group implementations into families we will use rarer and more reliably established relationships: shared code, shared authors, using one to bootstrap another.
|
||||
|
||||
### Лямбда-фанерозой
|
||||
### Lambda Phanerozoic
|
||||
|
||||
Что представляет из себя наша история имплементаций? В первую очередь - это история компиляторов в код обычных машин, в меньшей степени - история интерпретаторов и специальных аппаратных имплементаций. Мы выбираем компиляторы для обычных машин как наиболее успешное направление имплементации ФЯ. Раз уж они дожили до наших дней (в отличие от специального железа) и больше применялись для написания нетривиальных программ (в отличие от специального железа и интерпретаторов) про них просто больше известно, есть о чем писать. С другой стороны, компилятор достаточно масштабный проект, чтоб их было не слишком много (в отличие от интерпретаторов), так что у нас получается вполне обозримый набор достаточно подробных историй, а не бесконечные списки с немногословными описаниями. Мы, конечно же, опишем и часть истории интерпретаторов и специальных машин в той степени, в какой это необходимо для понимания истории компиляторов, но не ставим перед собой цели сколько-нибудь полно осветить этот вопрос.
|
||||
What is our history of implementations? First of all, it is a history of compilers into the code of ordinary machines, and to a lesser extent a history of interpreters and special hardware implementations. We choose compilers for ordinary machines as the most successful direction of implementing functional languages. Since they have survived to our day (unlike special hardware) and were more often used to write nontrivial programs (unlike special hardware and interpreters), there is simply more known about them, and more to write about. On the other hand, a compiler is a sufficiently large-scale project that there are not too many of them (unlike interpreters), so we get a fairly manageable set of fairly detailed histories rather than endless lists with terse descriptions. We will, of course, describe part of the history of interpreters and special machines to the extent that it is necessary for understanding the history of compilers, but we do not aim to cover this question fully.
|
||||
|
||||
Но и у истории имплементаций есть проблемы. История программирования не очень богата событиями, когда функциональные программисты не так уж много пишут нетривиальные программы. Что такое нетривиальные программы? Например, код компилятора этого или другого функционального языка, код интерактивного решателя теорем.
|
||||
Планка не выглядит высокой, но не для ФЯ, конечно. Причем, не то что-бы был какой-то выбор того где должна находится эта планка, потому что кроме того как быстро работают микробенчмарки и как быстро компилирует компилятор написанный на каком-нибудь ФЯ, мало что можно узнать.
|
||||
Можно прочесть про одни имплементации, что числа Фибоначчи вычисляются не сильно медленнее чем на C, и что на языке написан компилятор, компилирующий что-то за приемлемое время, а про другие прочесть то, что компилятор на них не написан, а производительность не так-то и важна.
|
||||
Поскольку история программирования и имплементаций сильно сдвинута к концу истории идей, она плохо ложиться на типичную для истории идей структуру "прогресса" и "формаций", когда все начинается с Лиспа, продолжается строгими ФЯ и завершается ленивыми. Вместо этого у нас после периода, когда ничего не работает, наступает период, когда заработало все и везде. Так что нам нужно как-то дополнительно структурировать "еще не работает" и "уже начинает работать".
|
||||
Нашу историю структурирует жизненный цикл имплементаций:
|
||||
Если имплементация достаточно старая, она могла долгие годы существовать как имплементация языка, который не похож на то, что мы определили как ФЯ в предыдущей главе. Например, Chez Scheme была использована как бэкенд для имплементации языка, который мы считаем ФЯ - Idris 2 - примерно после 35-илетней истории (если не считать один эксперимент).
|
||||
С течением времени, необходимые фичи в этот язык добавлялись, или для имплементации вовсе писался фронтенд для другого языка. Более новые имплементации уже могли с самого начала быть имплементациями ФЯ Эдинбургской программы.
|
||||
Если имплементация существует достаточно долго, то она используется для бутстрапа другой имплементации, написанной с самого начала уже на этом ФЯ. Если имплементация недостаточно успешна, то этого может и не произойти.
|
||||
У этого простого цикла "предыстория-хопизация-бутстрап" могут быть и другие осложнения, разветвления и т.д. но общая структура обычно видна.
|
||||
But the history of implementations also has problems. The history of programming is not very rich in events where functional programmers write many nontrivial programs. What are nontrivial programs? For example, the code of a compiler for one functional language or another, or the code of an interactive theorem prover.
|
||||
The bar does not look high, but not for functional languages, of course. And it is not as if there was any real choice about where this bar should be, because apart from how fast microbenchmarks run and how fast a compiler written in some functional language compiles, there is little to learn.
|
||||
You can read about some implementations that Fibonacci numbers are computed not much slower than in C, and that the language has a compiler that compiles something in acceptable time, and about others that no compiler was written in them and that performance is not that important.
|
||||
Because the history of programming and implementations is heavily shifted toward the end of the history of ideas, it fits poorly with the typical history-of-ideas structure of "progress" and "formations," where everything starts with Lisp, continues with strict functional languages, and ends with lazy ones. Instead, after a period when nothing works, we have a period when everything works everywhere. So we need to further structure "not working yet" and "already starting to work."
|
||||
Our history is structured by the life cycle of implementations:
|
||||
If an implementation is old enough, it could for many years exist as an implementation of a language that does not look like what we defined as functional languages in the previous chapter. For example, Chez Scheme was used as a backend to implement a language we consider a functional language - Idris 2 - after roughly 35 years of history (if we do not count one experiment).
|
||||
Over time, the necessary features were added to that language, or a frontend for another language was written for the implementation. Newer implementations could already, from the very beginning, be implementations of functional languages of the Edinburgh program.
|
||||
If an implementation exists long enough, it is used to bootstrap another implementation written from the start in that functional language. If an implementation is not successful enough, this may not happen.
|
||||
This simple "prehistory-hopization-bootstrap" cycle can have other complications, branching, and so on, but the overall structure is usually visible.
|
||||
|
||||
И последнее, но не наименее важное, история имплементаций ставит перед нами вопрос, ответ на который требует описывать и историю обычных машин и операционных систем, которую мы, разумеется, тоже будем описывать без каких-то претензий на полноту:
|
||||
Если идея функционального программирования, как это выяснили наши великие предшественники, существовала столько же, сколько и программирование или даже дольше, то почему функционального программирования не было? Когда оно могло бы уже появиться? И что было тогда, когда функционального программирования не было?
|
||||
And last, but not least, the history of implementations poses a question whose answer requires us to describe the history of ordinary machines and operating systems, which we will of course also describe without any claim to completeness:
|
||||
If the idea of functional programming, as our great predecessors established, existed as long as programming itself or even longer, then why was there no functional programming? When could it have already appeared? And what was there at that time when functional programming did not exist?
|
||||
|
||||
И, наконец-то, мы покончили с сильно затянувшимся предисловием к предисловию и у нас впереди сильно затянувшееся предисловие про сильно затянувшуюся эпоху, когда идея функционального программирования была, а функционального программирования не было, ведь первый компилятор функционального языка Эдинбургской исследовательской программы появился только в 1981-ом году.
|
||||
And finally, we are done with the overly long preface to the preface, and ahead of us is an overly long preface about an overly long era when the idea of functional programming existed, but functional programming did not, because the first compiler for a functional language of the Edinburgh research program appeared only in 1981.
|
||||
|
||||
Ветвь обоих Кембриджей
|
||||
The Branch of Both Cambridges
|
||||
======================
|
||||
|
||||
> Было сказано, в частности Морисом Уилксом, что этот проект был полным провалом и его не следовало и начинать.
|
||||
Мартин Ричардс, Кристофер Стрейчи и Кембриджский компилятор CPL [Rich2000]
|
||||
> It was said, in particular by Maurice Wilkes, that this project was a complete failure and should not have been started.
|
||||
Martin Richards, Christopher Strachey and the Cambridge CPL compiler [Rich2000]
|
||||
|
||||
> "Различные формы факториалов", рукопись 6 страниц, без даты
|
||||
Каталог статей и писем Кристофера Стрейчи [Strachey]
|
||||
> "Various forms of factorials," manuscript, 6 pages, undated
|
||||
Catalogue of the papers and correspondence of Christopher Strachey [Strachey]
|
||||
|
||||
|
||||
История функциональных языков отделилась от истории всех прочих языков, когда в одном Кембридже задумали сделать практичный функциональный язык общего назначения, а затем в другом Кембридже удалось имплементировать два языка: один из них был практичным языком общего назначения, а другой - функциональным.
|
||||
The history of functional languages separated from the history of all other languages when, in one Cambridge, they conceived a practical general-purpose functional language, and then in another Cambridge they managed to implement two languages: one was a practical general-purpose language and the other was functional.
|
||||
|
||||
Нужно заметить, что история языков с первоклассными функциями отделялась от истории всех прочих еще два или три раза, но Эдинбургская Исследовательская Программа произошла именно от этого, двойного кембриджского ответвления, которое называется так потому, что семейство языков разрабатывалось в основном исследователями, которые сначала поработали в одном Кембридже, а потом в другом Кембридже.
|
||||
It should be noted that the history of languages with first-class functions separated from the history of all other languages two or three more times, but the Edinburgh Research Program came precisely from this double Cambridge branch, which is so called because the family of languages was developed mainly by researchers who first worked in one Cambridge and then in the other Cambridge.
|
||||
|
||||
В Кембридже
|
||||
In Cambridge
|
||||
-----------
|
||||
|
||||
До начала истории имплементаций ФЯ была история ошибочных представлений о том, что такая имплементация уже может быть написана. И одним из первых их носителей был Кристофер Стрейчи (Christopher Strachey). В начале 60-х он работал консультантом и в этом качестве участвовал в проектировании компьютеров и разработке ПО. По-видимому, с переменным успехом, но мы не изучали этот вопрос глубоко. Его единственным сотрудником и вторым программистом компании с января 1960 был Питер Ландин (Peter Landin), который часть рабочего времени (согласованно со Стрейчи) тратил на исследования, которые имеют непосредственное отношение к истории ФП [Camp85], а именно: формальную семантику ЯП, трансляцию ЯП в ЛИ и виртуальную машину для интерпретации лямбда-выражений [Land64].
|
||||
Знакомый Стрейчи Морис Уилкс (Maurice Vincent Wilkes) руководил кембриджской математической (позднее - компьютерной) лабораторией (University Mathematical (Computer) Laboratory, Cambridge). Вместе со Стрейчи Уилкс критиковал ALGOL 60 [Stra61] за отсутствие синтаксических различий между чистыми и прочими, рекурсивными и нерекурсивными функциями. В этой их работе появились первые наброски CPL [Rich13]
|
||||
Before the history of implementations of functional languages there was a history of mistaken ideas that such an implementation could already be written. One of the first bearers of these ideas was Christopher Strachey. In the early 1960s he worked as a consultant and in that capacity took part in computer design and software development. Apparently with mixed success, but we did not study this question deeply. His only colleague and the company's second programmer from January 1960 was Peter Landin, who spent part of his working time (by agreement with Strachey) on research directly related to the history of FP [Camp85], namely formal semantics of programming languages, translation of programming languages into the lambda calculus, and a virtual machine for interpreting lambda expressions [Land64].
|
||||
A colleague of Strachey, Maurice Vincent Wilkes, headed the Cambridge Mathematical (later Computer) Laboratory (University Mathematical (Computer) Laboratory, Cambridge). Together with Strachey, Wilkes criticized ALGOL 60 [Stra61] for the lack of syntactic distinctions between pure and other functions, recursive and non-recursive functions. In this work the first sketches of CPL appeared [Rich13].
|
||||
|
||||
### CPL
|
||||
|
||||
Летом 62-го Уилкс пригласил Стрейчи работать в свою лабораторию для участия в разработке языка и компилятора для нового компьютера Titan (позднее Atlas 2 [TITAN]), который лаборатория должна была получить через два года [Camp85]. Переход Стрейчи из консультантов в академики плохо сказывался на его доходах, но это должна была скомпенсировать уникальная возможность поучаствовать в проектировании и имплементации опередившего свое время языка. Именно поучаствовать в проектировании и имплементации, а не спроектировать и имплементировать, потому что, забегая вперед, этого так и не произошло. Язык опередит и существующие в то время возможности его имплементировать.
|
||||
In the summer of 1962 Wilkes invited Strachey to work in his laboratory to participate in developing a language and compiler for a new computer, Titan (later Atlas 2 [TITAN]), which the laboratory was to receive two years later [Camp85]. Strachey's move from consulting to academia hurt his income, but this was supposed to be compensated by the unique opportunity to participate in the design and implementation of a language ahead of its time. To participate in the design and implementation, not to design and implement it, because, to anticipate, that never happened. The language would outrun the existing capabilities of its time to implement it.
|
||||
|
||||
Первый пропозал CPL (Cambridge Programming Language) был написан Стрейчи, Девидом Барроном (David W. Barron) и Девидом Хартли (David F. Hartley) (которого Стрейчи при первой встрече за несколько лет до того отговорил имплементировать ALGOL 60 [Hart2000]) в августе 62-го. Но уже осенью, по инициативе Баррона и Хартли [Hart2000] [Hart13], начинается сотрудничество с университетом Лондона (London University Computer Unit), который ожидал старшую версию компьютера из той же линейки - Atlas [ATLAS]. К авторам присоединяются Эрик Никсон (Eric Nixon) и Джон Бакстон (John N. Buxton), а CPL становится Combined Programming Language. О Питере Ландине вспоминают как о участнике разработки языка [Rich2000], хотя официально он над языком не работал.
|
||||
В феврале 63 готова статья “The Main Features of CPL” [Barr63].
|
||||
Не смотря на схожесть компьютеров, каждый университет пишет свою имплементацию CPL [Rich13]. Лондон - более традиционную, а Кембридж - более экспериментальную, основанную на идеях Ландина, видимо о компиляции через промежуточный язык "аппликативных выражений".
|
||||
Но с октября 63-го обе команды имплементаторов совещаются каждый месяц.
|
||||
Встречи комитета частые, долгие и запоминающиеся [Rich2000].
|
||||
В Кембридже имплементацию планируют закончить в начале 64-го, ко времени получения Titan.
|
||||
The first CPL (Cambridge Programming Language) proposal was written by Strachey, David W. Barron, and David F. Hartley (whom Strachey had talked out of implementing ALGOL 60 at their first meeting several years earlier [Hart2000]) in August 1962. But already in the fall, on the initiative of Barron and Hartley [Hart2000] [Hart13], collaboration began with the London University Computer Unit, which was expecting a higher-end computer from the same line, Atlas [ATLAS]. Eric Nixon and John N. Buxton joined the authors, and CPL became the Combined Programming Language. Peter Landin is recalled as a participant in the language's development [Rich2000], although officially he did not work on the language.
|
||||
In February 1963 the paper "The Main Features of CPL" was ready [Barr63].
|
||||
Despite the similarity of the computers, each university wrote its own CPL implementation [Rich13]. London wrote a more traditional one, and Cambridge a more experimental one, based on Landin's ideas, apparently about compiling via an intermediate language of "applicative expressions."
|
||||
But from October 1963 both teams of implementers met every month.
|
||||
The committee meetings were frequent, long, and memorable [Rich2000].
|
||||
In Cambridge they planned to finish the implementation in early 1964, by the time Titan arrived.
|
||||
|
||||
Но Стрейчи все больше переключался на формальное описание семантики, которым заинтересовался под влиянием Ландина. Баррон, один из самых активных участников сначала, тоже переключился на другие дела, хотя какое-то время участвовал в совещаниях, но компилятором уже не занимался. Над компилятором работали аспиранты, года по три, причем последний из трех в основном над своей диссертацией [Rich13] [Hart13].
|
||||
But Strachey increasingly switched to formal semantic description, which he became interested in under Landin's influence. Barron, one of the most active participants at first, also switched to other matters, although he participated in meetings for some time, but no longer worked on the compiler. Graduate students worked on the compiler for about three years each, and the last of the three mainly worked on his dissertation [Rich13] [Hart13].
|
||||
|
||||
Летом 64-го Уилкс, недовольный медленной работой над компилятором, назначил руководителем команды имплементаторов Дэвида Парка (David Park), работавшего в Оксфорде и МТИ и имевшего опыт имплементации ЯП. Это не помогло. Вклад Стрейчи все сокращался, ему было не интересно работать над практичной имплементацией, да она и не получалась: предварительная версия компилятора работала медленно, в чем обвинили новаторский подход.
|
||||
Только вот лондонская имплементация тоже не была завершена, удалось имплементировать только непрактичный компилятор подмножества CPL.
|
||||
Фактически, над обеими имплементациями более-менее постоянно работало по одному человеку: компилятор в Лондоне писал Джордж Кулурис (George Coulouris) [Coul], а кембриджский компилятор писал Мартин Ричардс (Martin Richards) - важный герой нашей истории, к которому мы еще вернемся.
|
||||
В 65 Стрейчи уходит из Кембриджа в МТИ на год, а потом в апреле 66-го в Оксфорд. Дэвид Парк тоже уходит из Кембриджа работать со Стрейчи в Оксфорде.
|
||||
Все это время, впрочем, Стрейчи работает над описанием CPL, что идет не очень хорошо, потому что он годами может взаимодействовать с прочими авторами только по переписке.
|
||||
В июне 66 комитет назначает Стрейчи редактором мануала, после чего большинство участников уходят из комитета официально потому, что уже и так занимались другими вещами.
|
||||
Этот мануал не был опубликован, но циркулировал как самиздат [Stra66b]. Проект в Кембридже завершился в декабре 66-го [Rich13]. Тогда же, в декабре 1966, состоялась последняя встреча комитета, на которой договорились прекратить работу. [Hart13]
|
||||
Джордж Кулурис в Лондоне написал компилятор подмножества CPL под названием CPL1 к осени 67-го [Coul68]. Этот компилятор описывают как более-менее законченный, но компилирующий только небольшие программы и непригодный для практического использования [Hart13]. Кембриджский компилятор описывают как непрактичный в лучшем случае [Rich13] или как вовсе не законченный [Hart13], как полный провал по мнению директора лаборатории [Rich2000]. Те, кому не нравится считать CPL "полным провалом", находили утешение в том, что CPL хоть и был неудачей по обычным стандартам, вроде известности, соблюдения сроков и эффективности имплементаций, но повлиял на другие языки [Camp85] [Rich2000]. Утешение в этом будут находить и следующие поколения дизайнеров и имплементаторов ФЯ.
|
||||
Участники проекта в своих воспоминаниях объясняют провал проекта потерей интереса: Баррон и Хартли занялись ОС для Titan/Atlas 2, а Стрейчи и Парк - формальной семантикой ЯП [Hart13]. Только вот это была не первая и не последняя неудачная попытка сделать компилятор ФЯ. Что если не прогресс остановился из-за потери интереса, а интерес был потерян из-за остановки прогресса по другим причинам? К выяснению того, что это были за причины мы еще вернемся.
|
||||
CPL задумывался как единый универсальный язык общего назначения [Hart13], но комитет, не смотря на практически полное согласие со Стрейчи [Hart2000] [Rich2000], мало что функционального специфицировал, а имплементировано было еще меньше. И CPL распался на диалекты: тот, что удалось имплементировать в Кембридже, тот, что удалось имплементировать в Лондоне. Для написания имплементации в Кембридже в 65-66гг. выделили самое простое подмножество из всех - практически виртуальную машину [Rich13]. Наконец, самый известный и влиятельный CPL - тот, что имплементировать было непонятно как, да и не стали пытаться.
|
||||
In the summer of 1964 Wilkes, dissatisfied with the slow work on the compiler, appointed David Park, who had worked in Oxford and MIT and had experience implementing programming languages, as the head of the implementation team. This did not help. Strachey's contribution kept shrinking; he was not interested in working on a practical implementation, and it was not working out: the preliminary version of the compiler ran slowly, which was blamed on the innovative approach.
|
||||
But the London implementation was not completed either; they only managed to implement an impractical compiler for a subset of CPL.
|
||||
In fact, each implementation had more or less one person working on it continuously: the compiler in London was written by George Coulouris [Coul], and the Cambridge compiler was written by Martin Richards - an important hero of our story whom we will return to later.
|
||||
In 1965 Strachey left Cambridge for MIT for a year, and then in April 1966 for Oxford. David Park also left Cambridge to work with Strachey in Oxford.
|
||||
All this time, however, Strachey worked on the CPL description, which went poorly because for years he could interact with the other authors only by correspondence.
|
||||
In June 1966 the committee appointed Strachey editor of the manual, after which most participants left the committee officially because they were already engaged in other things.
|
||||
This manual was not published, but circulated as samizdat [Stra66b]. The Cambridge project ended in December 1966 [Rich13]. That same December 1966 saw the last committee meeting, where they agreed to stop work [Hart13].
|
||||
George Coulouris in London wrote a compiler for a CPL subset called CPL1 by autumn 1967 [Coul68]. This compiler is described as more or less finished, but compiling only small programs and unsuitable for practical use [Hart13]. The Cambridge compiler is described as impractical at best [Rich13] or not finished at all [Hart13], and as a complete failure in the opinion of the laboratory director [Rich2000]. Those who dislike calling CPL a "complete failure" found consolation in the fact that CPL, though a failure by usual standards such as fame, deadlines, and implementation efficiency, influenced other languages [Camp85] [Rich2000]. Later generations of functional-language designers and implementers would find consolation in this too.
|
||||
Project participants in their recollections explain the project's failure by loss of interest: Barron and Hartley took up the OS for Titan/Atlas 2, and Strachey and Park took up formal semantics of programming languages [Hart13]. But this was not the first and not the last failed attempt to make a functional-language compiler. What if progress did not stop because of lost interest, but interest was lost because progress stopped for other reasons? We will return to finding out what those reasons were.
|
||||
CPL was conceived as a single universal general-purpose language [Hart13], but the committee, despite near-complete agreement with Strachey [Hart2000] [Rich2000], specified little that was functional, and even less was implemented. CPL split into dialects: the one they managed to implement in Cambridge, and the one they managed to implement in London. To write the Cambridge implementation in 1965-66 they selected the simplest subset of all - practically a virtual machine [Rich13]. Finally, the most famous and influential CPL is the one that was unclear how to implement, and they did not even try.
|
||||
|
||||
### псевдоCPL
|
||||
### pseudoCPL
|
||||
|
||||
Летом 63-го года Стрейчи, Баррон и Филип Вудвард (Philip Woodward) из Королевского института радиолокации прочли несколько лекций по программированию с примерами на "CPL" [Wood66] [Stra66]. Эти лекции были изданы в сборнике в 1966 [Fox66].
|
||||
In the summer of 1963 Strachey, Barron, and Philip Woodward of the Royal Radar Establishment gave several lectures on programming with examples in "CPL" [Wood66] [Stra66]. These lectures were published in a collection in 1966 [Fox66].
|
||||
|
||||
Важно уточнить, что код и в этих статьях, и даже в статье, называющейся "Основные фичи CPL" [Barr63] не является кодом на какой-то версии CPL, которая была описана комитетом и тем более имплементирована. Интересно, что и автор лондонской имплементации Кулурис посчитал нужным явно написать, что нет, написать примеры с помощью CPL из мануала [Stra66b] или имплементированного в Лондоне CPL1 нельзя [Coul68].
|
||||
It is important to clarify that the code in these articles, and even in the article titled "The Main Features of CPL" [Barr63], is not code in any version of CPL that was described by the committee, let alone implemented. Interestingly, the author of the London implementation, Coulouris, also found it necessary to explicitly write that no, it is not possible to write the examples using the CPL from the manual [Stra66b] or the CPL1 implemented in London [Coul68].
|
||||
|
||||
Это был гораздо более впечатляющий CPL, который был настолько хорошим языком, насколько Стрейчи хотел, чтоб он был, без всяких рамок которые могла накладывать имплементация или даже непротиворечивость самого языка, который мы будем называть _псевдоCPL_.
|
||||
Стрейчи просто писал `map` и `foldr` (который называл `Lit`)
|
||||
This was a much more impressive CPL, as good a language as Strachey wanted it to be, without any constraints that implementation or even internal consistency could impose, which we will call _pseudoCPL_. Strachey simply wrote `map` and `foldr` (which he called `Lit`)
|
||||
|
||||
```haskell
|
||||
let Map[f, L] = Null[L] -> NIL,
|
||||
|
|
@ -341,11 +340,11 @@ let Lit[F, z, L] = Null[L] -> z,
|
|||
Lit[F1, 1, (1, 2, 3)] where F1[x,y] = x * y
|
||||
```
|
||||
|
||||
не зная как его можно имплементировать и можно ли вообще.
|
||||
Как, сделать так, чтоб в коде типизированного языка не было аннотаций типов? Стрейчи даже не написал, что знает как это сделать, но алгоритм не поместился на полях. Что поделать, выхода у будущих имплементаторов ФЯ не было, пришлось придумать способ и не один.
|
||||
И тот, кто хотел аннотировать типы и рекурсию и тот, кто не хотел, могли помнить о псевдоCPL как о языке, который им нравился, и который они хотели бы повторить. Со временем, так научатся делать и с имплементированными языками. Но до этого пока далеко.
|
||||
without knowing how it could be implemented or whether it could be implemented at all.
|
||||
How do you make it so that code in a typed language has no type annotations? Strachey did not even write that he knew how to do this, but the algorithm did not fit in the margins. There was no way out for future functional-language implementers; they had to invent a way, and more than one.
|
||||
Both those who wanted to annotate types and recursion and those who did not could remember pseudoCPL as a language they liked and wanted to reproduce. In time, they would learn to do this with implemented languages as well. But that is still far away.
|
||||
|
||||
Эта идея не была новой. За три года до того уже выходила статья с примерами кода на языке, название которого совпадало с названием языка, который в это время имплементировался. Разумеется, эта имплементация также не поддерживала код из статьи:
|
||||
This idea was not new. Three years earlier there was already an article with code examples in a language whose name matched the language being implemented at the time. Of course, that implementation also did not support the code from the article:
|
||||
|
||||
```haskell
|
||||
maplist[x; f] = [null[x] -> NIL;
|
||||
|
|
@ -354,12 +353,12 @@ maplist[x; f] = [null[x] -> NIL;
|
|||
maplist[(1,2,3); λ[[x]; x + y]]
|
||||
```
|
||||
|
||||
(пример в статье отличается отсутствием вызова car)
|
||||
(the example in the article differs by the absence of a `car` call)
|
||||
|
||||
Мечты о ФП коде в лекциях Стрейчи и д.р. - итерация похожих мечт из этой статьи про Лисп [McCa60], которой оказалось для многих достаточно, чтоб считать Лисп первым ФЯ.
|
||||
Псевдокод не похож на Лисп? Ну да, Лисп-первый-ФЯ не состоялся. Планировалось, что Лисп будет выглядеть так. Это M-выражения, которые не были ни имплементированы, ни даже специфицированы потому, что имплементация фронтенда все затягивалась, и лисперы привыкли писать на промежуточном коде - S-выражениях. В результате, написание транслятора из M в S выражения было заброшено. Но для имплементации ФЯ важнее то, что не заработала как надо передача функций в функции [McCa78]. К этой проблеме мы еще вернемся.
|
||||
Dreams of FP code in Strachey's lectures and others are an iteration of similar dreams from this article on Lisp [McCa60], which was enough for many to consider Lisp the first functional language.
|
||||
Pseudocode does not look like Lisp? Yes, the Lisp-as-first-functional-language story did not happen. It was planned that Lisp would look like this. These are M-expressions, which were neither implemented nor even specified because the frontend implementation kept being delayed, and Lispers got used to writing in intermediate code - S-expressions. As a result, writing a translator from M to S expressions was abandoned. But for implementing functional languages, the more important thing is that passing functions to functions did not work properly [McCa78]. We will return to this problem.
|
||||
|
||||
Можно было бы сказать, что основная новация CPL-ной итерации в том, что работать со списками теперь собирались в типизированном языке. Но сложно назвать инновацией одно только намерение это сделать. Ни во время чтения этих лекций, ни во время их издания еще толком не понимали как такой код типизировать. Если посмотреть на расширения ALGOL 60, которые в то время имплементировали в Королевском институте радиолокации [Wood66]
|
||||
One might say that the main innovation of the CPL iteration was that list processing was now intended to be done in a typed language. But it is hard to call it an innovation to merely intend to do so. Neither when these lectures were delivered nor when they were published did they really know how to type such code. If you look at the ALGOL 60 extensions that were being implemented at the Royal Radar Establishment at that time [Wood66]
|
||||
|
||||
```pascal
|
||||
list procedure Append(x, y); list x, y;
|
||||
|
|
@ -367,36 +366,36 @@ Append := if Null(x) then y else
|
|||
Cons(Hd(x), Append(Tl(x), y))
|
||||
```
|
||||
|
||||
то видно, что тип списка просто `list` без параметра. Но во времена ALGOL 60 не знали и как функции нормально типизировать, там и тип функции параметризован только по возвращаемому типу, например `real procedure`. Правда, в 1967-ом кое-какие идеи на этот счет у Стрейчи появились.
|
||||
you can see that the list type is just `list` without a parameter. But in the days of ALGOL 60 they also did not know how to type functions properly; the function type was parameterized only by the return type, for example `real procedure`. It is true that in 1967 Strachey had some ideas about this.
|
||||
|
||||
К сожалению, не на всех производит впечатление псевдокод в статьях, многие важные имплементаторы ФЯ вспоминают, что на них произвели впечатление работающие вещи. [Turn12][TODO Леннарт Августссон, Марк Джонс, Ксавье Леруа] Но эти работающие вещи для них сделали те, кто просто не мог смириться с тем, что такой фантастический язык остается фантастическим. И позднее они придумали и имплементировали языки, на которых можно писать `map` именно так, а можно и лучше.
|
||||
Unfortunately, not everyone is impressed by pseudocode in papers; many important functional-language implementers recall that what impressed them were working things. [Turn12][TODO Lennart Augustsson, Mark Jones, Xavier Leroy] But those working things were made for them by people who simply could not accept that such a fantastic language remained fantastic. And later they invented and implemented languages in which you could write `map` exactly like that, or even better.
|
||||
|
||||
И писать так `map` они хотели достаточно долго, чтоб атавизмы этого стиля вроде `head` и `tail` попали в ФЯ и дожили до наших дней, хотя сам стиль устарел еще до первой практической имплементации.
|
||||
And they wanted to write `map` like that for long enough that atavisms of this style, such as `head` and `tail`, entered functional languages and survived to our day, even though the style itself became obsolete before the first practical implementation.
|
||||
|
||||
### Следующие 700 непопулярных языков
|
||||
### The Next 700 Unpopular Languages
|
||||
|
||||
> <Я> надеялся <...> сдержать создание сомнительных языков программирования, называемых (как группа) OWHY, что означает "Or What Have You". Никто не понял шутки, и попытка была обречена.
|
||||
> Дана Скотт, A type-theoretical alternative to ISWIM, CUCH, OWHY, 1993 [Scot93]
|
||||
> <I> hoped <...> to restrain the creation of dubious programming languages, called (as a group) OWHY, which means "Or What Have You." Nobody got the joke, and the attempt was doomed.
|
||||
> Dana Scott, A type-theoretical alternative to ISWIM, CUCH, OWHY, 1993 [Scot93]
|
||||
|
||||
|
||||
CPL разрабатывался в первую очередь как практичный императивный ФЯ с добавленными функциональными фичами, в реальность которого верили и имплементацию ждали [Wood66], но фантазии про который сильно опередили его имплементацию.
|
||||
Параллельно с ним, в обоекембриджской программе развивался второй язык - ISWIM, который двигался в противоположном направлении.
|
||||
CPL was developed primarily as a practical imperative functional language with added functional features, a language whose reality people believed in and whose implementation they expected [Wood66], but the fantasies about it far outpaced its implementation.
|
||||
In parallel, in the two-Cambridge program, a second language was developing - ISWIM, which moved in the opposite direction.
|
||||
|
||||
#### Следующие 700 исписанных листов
|
||||
#### The Next 700 Written Pages
|
||||
|
||||
ISWIM (или YSWIM в черновиках [Landin]), что означало "If you See What I Mean", описывал в серии статей Питер Ландин.
|
||||
Сначала как чисто функциональный псевдокод для описания спецификаций, транслируемый в лямбда-исчисление [Land64]. Затем как императивный псевдокод, транслируемый в лямбда-исчисление, расширенное добавлением мутабельности и средствами захвата продолжения для имплементации произвольного потока исполнения [Land98]. И все еще для описания спецификации, теперь уже ALGOL 60 [Land65a] [Land65b].
|
||||
Наконец, как "попытку сделать систему общего назначения для описания одних вещей в терминах других вещей, которая может быть проблемно-ориентированной при подходящем выборе примитивов." [Land66]. Неостановимую фабрику ФЯ, следующие 700 языков программирования.
|
||||
Эти встречные движения привели к тому, что псевдоCPL и ISWIM, а точнее их функциональные подмножества оказались примерно в одном и том же месте и разбор отдельных фич для каждого был бы слишком повторяющимся, так что собран в одной главе.
|
||||
На ISWIM написаны, по видимому, более крупные фрагменты ФП псевдокода, чем на CPL.
|
||||
Самый крупный из них - парсер ALGOL 60 в абстрактное синтаксическое дерево, его описание, компиляция этого дерева в императивные аппликативные выражения IAE. Всего ~500LOC функционального псевдокода [Land65b].
|
||||
Предполагалось, что такое описание семантики можно "исполнять" вручную, с помощью ручки и бумаги, но на практике это, конечно, едва ли осуществимо.
|
||||
Такой подход к описанию семантики - как наивного интерпретатора написанного на ФЯ - имеет смысл только при механизации этой "семантики", когда интерпретатор действительно работает, как у авторов Clean в восьмидесятые или, например, у Россберга в десятые.
|
||||
Так что, по крайней мере попытка имплементации была неизбежна. И именно от этой неизбежной механизации "семантики" останется литература по имплементации ФЯ, но о ней позже.
|
||||
Сложно точно установить что на что повлияло в случае функциональных подмножеств CPL и ISWIM.
|
||||
Ландин написал статьи в первом приближении еще во время работы у Стрейчи [Land65b], т.е. в 60-62 годах [Camp85], прочитал по ним лекции в 63-ем [Fox66], но опубликовал позднее, когда работал в Univac подразделении Sperry Rand и МТИ.
|
||||
Функциональное подмножество ISWIM может быть старее CPL, но выглядит современнее и с меньшими странностями. Но современнее выглядит просто то, что больше понравилось авторам современных языков.
|
||||
Очередная функция `map`, на этот раз на ISWIM 65 [Land65b]
|
||||
ISWIM (or YSWIM in drafts [Landin]), which meant "If you See What I Mean," was described in a series of articles by Peter Landin.
|
||||
First as purely functional pseudocode for describing specifications, translated into the lambda calculus [Land64]. Then as imperative pseudocode translated into the lambda calculus extended with mutability and continuation-capture facilities to implement arbitrary control flow [Land98]. And still for describing a specification, now ALGOL 60 [Land65a] [Land65b].
|
||||
Finally, as "an attempt to make a general-purpose system for describing some things in terms of other things, which can be problem-oriented with an appropriate choice of primitives" [Land66]. An unstoppable factory of functional languages, the next 700 programming languages.
|
||||
These opposing movements led to pseudoCPL and ISWIM - or rather their functional subsets - ending up in roughly the same place, and analyzing individual features for each would be too repetitive, so they are gathered in one chapter.
|
||||
ISWIM contains, apparently, larger fragments of FP pseudocode than CPL.
|
||||
The largest of them is an ALGOL 60 parser into an abstract syntax tree, its description, and compilation of that tree into imperative applicative expressions (IAE). In total about 500 LOC of functional pseudocode [Land65b].
|
||||
It was assumed that such a semantic description could be "executed" by hand, with pen and paper, but in practice this is, of course, hardly feasible.
|
||||
This approach to describing semantics - as a naive interpreter written in a functional language - makes sense only when that "semantics" is mechanized, when the interpreter actually works, as with the authors of Clean in the 1980s or, for example, Rossberg in the 2010s.
|
||||
So at least an attempt at implementation was inevitable. And it is from this inevitable mechanization of "semantics" that the literature on functional-language implementation remains, but more on that later.
|
||||
It is hard to determine exactly what influenced what in the case of the functional subsets of CPL and ISWIM.
|
||||
Landin wrote the articles in a first approximation while still working with Strachey [Land65b], i.e., in 1960-62 [Camp85], lectured from them in 1963 [Fox66], but published them later when he worked at the Univac division of Sperry Rand and at MIT.
|
||||
The functional subset of ISWIM may be older than CPL, but it looks more modern and with fewer oddities. But what looks more modern is simply what the authors of modern languages liked more.
|
||||
Another `map` function, this time in ISWIM 65 [Land65b]
|
||||
|
||||
```haskell
|
||||
rec map f L = null L -> ()
|
||||
|
|
@ -405,92 +404,92 @@ rec map f L = null L -> ()
|
|||
map f (1, 2, 3) where f x = x * y and y = 1
|
||||
```
|
||||
|
||||
В Univac к ISWIM проекту присоединился Уильям Бердж (William H. Burge), описывающий типизированные аппликативные выражения TAE [Burg64] [Burg66].
|
||||
At Univac, William H. Burge joined the ISWIM project, describing typed applicative expressions (TAE) [Burg64] [Burg66].
|
||||
|
||||
#### Следующие 700 вариаций семи фич
|
||||
#### The Next 700 Variations of Seven Features
|
||||
|
||||
CPL разрабатывался на основе ALGOL 60 [Rich13] [Hart13]. В описании ISWIM ссылаются на псевдоLISP 60-го года и ALGOL 60 [Land66].
|
||||
"Основа Алгола" в это время - лексическая видимость и поддержка рекурсии. То, что обычно авторы языков и заимствовали из Алгола. Для заимствования этих идей не нужно знать ALGOL 60, если знать про лямбда-исчисление, но многие изобретатели ФП ссылаются на влияние и ЛИ и ALGOL 60. Почему так происходило нам не понятно. Свойства ALGOL 60 по всей видимости не являются изобретенными независимо от ЛИ, а являются следами частично успешной борьбы меньшинства комитета за то, чтоб сделать ALGOL ФЯ [Naur78]. Эта борьба не закончилась на ALGOL 60 и к ней мы еще вернемся. Возможно, ссылающимся на ALGOL была важнее доказанная практикой возможность имплементации.
|
||||
Синтаксические решения из ALGOL 60 в ISWIM и CPL в основном не попали, о некоторых исключениях - ниже. Не попали и непопулярные, среди заимствующих из Алгола, фичи вроде передачи параметров по имени.
|
||||
CPL - язык со множеством императивных фич, которые оказали серьезное влияние на мейнстрим. Также, со множеством странных фич. Вроде двух разновидностей имен - однобуквенных из строчной буквы и нуля и более праймов и многобуквенных, начинающихся с заглавной и могущих включать в себя числа. Для чего? Чтоб умножение могло быть не оператором, а отсутствием оператора.
|
||||
CPL was developed based on ALGOL 60 [Rich13] [Hart13]. The ISWIM description refers to pseudo-LISP from 1960 and ALGOL 60 [Land66].
|
||||
The "core of ALGOL" at that time was lexical scope and support for recursion. These are the things language authors usually borrowed from ALGOL. To borrow these ideas you do not need to know ALGOL 60 if you know lambda calculus, but many FP inventors refer to the influence of both lambda calculus and ALGOL 60. Why this happened is not clear to us. The properties of ALGOL 60 apparently were not invented independently of lambda calculus, but are traces of a partially successful struggle by a minority of the committee to make ALGOL a functional language [Naur78]. This struggle did not end with ALGOL 60 and we will return to it. Perhaps for those citing ALGOL, the proven possibility of implementation in practice was more important.
|
||||
Syntactic solutions from ALGOL 60 largely did not make it into ISWIM and CPL; we will discuss some exceptions below. Unpopular features among those borrowing from ALGOL, such as call-by-name parameters, also did not make it.
|
||||
CPL is a language with many imperative features that had a serious influence on the mainstream. It also has many strange features. For example, two kinds of names: single-letter ones consisting of a lowercase letter and zero or more primes, and multi-letter ones starting with a capital and allowed to include numbers. Why? So that multiplication could be not an operator, but the absence of an operator.
|
||||
|
||||
```
|
||||
Square[x] = xx
|
||||
```
|
||||
|
||||
Но не все странные фичи CPL остались в CPL, некоторые присутствовали и в ISWIM и оказали влияние на Эдинбургскую исследовательскую программу.
|
||||
But not all of CPL's strange features remained in CPL; some were also present in ISWIM and influenced the Edinburgh research program.
|
||||
|
||||
##### больше не фичи
|
||||
##### No Longer Features
|
||||
|
||||
Этот класс странных фич как раз демонстрирует происхождение Эдинбургских языков от CPL/ISWIM, странными они стали только исчезнув из этих языков в 80-х и 90-х годах. Какой еще язык претендует на то, что от него произошли языки эдинбургской программы, и эта претензия более-менее правдоподобна без учета этих странных фич? Не все сразу!
|
||||
This class of strange features demonstrates the origin of the Edinburgh languages from CPL/ISWIM; they became strange only after disappearing from these languages in the 1980s and 1990s. What other language claims that the Edinburgh program languages descended from it, and that this claim is more or less plausible without taking these strange features into account? Not all at once!
|
||||
|
||||
###### отсутствие лямбд
|
||||
###### Absence of Lambdas
|
||||
|
||||
Отсутствие лямбды довольно неожиданная особенность для ФЯ, и за пределами круга разработчиков CPL/ISWIM идея захватила только еще одного автора ФЯ.
|
||||
И не смотря на то, что это автор нескольких влиятельных языков, и многие имплементаторы ФЯ хотели делать языки как у него, всего этого влияния не хватило для того чтоб популяризировать ФЯ без лямбд. И едва ли для кого-то такой результат покажется неожиданным.
|
||||
Нам не удалось установить почему лямбда не попала в CPL/ISWIM. Возможно, это наследие ALGOL 60. Возможно потому, что авторы увлеклись эквивалентной конструкцией, которую считали одной из основных фич обоекембриджских языков и хотели использовать только ее. Эта фича -
|
||||
The absence of lambda is a rather unexpected feature for a functional language, and outside the circle of CPL/ISWIM developers the idea captured only one more functional-language author.
|
||||
And despite the fact that this author created several influential languages, and many functional-language implementers wanted to make languages like his, all of that influence was not enough to popularize functional languages without lambdas. And this result will hardly seem surprising to anyone.
|
||||
We were unable to determine why lambda did not make it into CPL/ISWIM. Perhaps it is a legacy of ALGOL 60. Perhaps because the authors became fascinated with an equivalent construct that they considered one of the main features of the two-Cambridge languages and wanted to use only it. That feature is -
|
||||
|
||||
###### выражение `where`
|
||||
###### `where` expression
|
||||
|
||||
Что делать, если лямбд нет, а хочешь написать
|
||||
What do you do if there are no lambdas, but you want to write
|
||||
|
||||
```haskell
|
||||
Quad [a, b, \x -> G[x, y]]
|
||||
```
|
||||
|
||||
? Нужно писать [Barr63]
|
||||
? You need to write [Barr63]
|
||||
|
||||
```haskell
|
||||
Quad [a, b, F] where F[x] = G[x, y]
|
||||
```
|
||||
|
||||
Выражение `where` - полный аналог современного `let` `in`, а не производная и гораздо более новая фича `where`-как-часть-других-конструкций, известная по Haskell.
|
||||
В наши дни выражение `where` полностью заменено на `let` и `where` как часть других конструкций. И хотя уже в 66-ом в описании [Stra66b] обсуждается какая-то смутная неудовлетворенность `where`-выражением и неопределенные планы сделать `where`-как-часть-декларации, фича существовала десятилетиями. Причем `where`-выражение не осталось только в мертвых языках, не попав в современные, а успело побывать в дизайне и имплементациях Haskell, Standard ML и Caml. Редкий пример фичи, которая попала в эти языки и не осталась в них навсегда.
|
||||
Авторы CPL не претендовали на изобретение `where`, утверждая, [Barr63] что позаимствовали конструкцию из калькулятора GENIE [Ilif61], но не в точности. В GENIE вместо ключевого слова `where` использовалась запятая.
|
||||
The `where` expression is a full analogue of the modern `let` `in`, not the derivative and much newer feature `where`-as-part-of-other-constructs known from Haskell.
|
||||
Today the `where` expression has been completely replaced by `let` and by `where` as part of other constructs. And although already in 1966 the description [Stra66b] discusses some vague dissatisfaction with the `where` expression and undefined plans to make `where`-as-part-of-declarations, the feature existed for decades. Moreover, the `where` expression did not remain only in dead languages, never making it into modern ones; it appeared in the design and implementations of Haskell, Standard ML, and Caml. A rare example of a feature that entered these languages and did not stay forever.
|
||||
The authors of CPL did not claim to have invented `where`, stating [Barr63] that they borrowed the construct from the GENIE calculator [Ilif61], though not exactly. In GENIE a comma was used instead of the `where` keyword.
|
||||
|
||||
###### тернарный оператор ветвления
|
||||
###### ternary branching operator
|
||||
|
||||
попал в мейнстрим, но в ФЯ вытеснен конструкциями из ключевых слов и частью других конструкций - гардами, на синтаксис которых он, вероятно повлиял, но не так сильно как синтаксис ветвления в псевдолиспе из [McCa60], возможно через синтаксис ISWIM 64.
|
||||
It entered the mainstream, but in functional languages it was displaced by keyword-based constructs and by parts of other constructs - guards - whose syntax it likely influenced, but not as strongly as the branching syntax in the pseudo-Lisp of [McCa60], possibly via the syntax of ISWIM 64.
|
||||
|
||||
```haskell
|
||||
let rec fact(n) = n = 0 -> 1, n * fact(n-1)
|
||||
```
|
||||
|
||||
В первом коде на ML (LCF 77) почти всегда используется тернарный оператор, а не `if then else` конструкция.
|
||||
In the first code in ML (LCF 77) the ternary operator is used almost always, rather than the `if then else` construct.
|
||||
|
||||
##### пока еще фичи
|
||||
##### Still Features
|
||||
|
||||
###### конструкция `let`
|
||||
###### `let` construct
|
||||
|
||||
В CPL `let` это часть синтаксиса деклараций, и `where` определяется через декларацию в возвращающем ссылку на значение блоке [Stra66b].
|
||||
In CPL, `let` is part of the declaration syntax, and `where` is defined through a declaration in a value-returning block [Stra66b].
|
||||
|
||||
```haskell
|
||||
E where D === ref of § let D; result is E §
|
||||
```
|
||||
|
||||
Но в ISWIM `let` - выражение [Land65a], вводится как сахар для `where` [Land66]
|
||||
But in ISWIM, `let` is an expression [Land65a], introduced as sugar for `where` [Land66]
|
||||
|
||||
```haskell
|
||||
let x = M; L === L where x = M
|
||||
```
|
||||
|
||||
###### аннотация рекурсии
|
||||
###### recursion annotation
|
||||
|
||||
Одна из первых идей для CPL еще из критики ALGOL 60 [Stra61], которая повлияла на языки Эдинбургской программы - аннотация рекурсии. В своей конечной и наиболее популярной форме - с помощью ключевых слов `rec` и `and`.
|
||||
Для ALGOL 60 такие аннотации рассматривали, но отклонили с небольшим перевесом [Naur78]
|
||||
One of the early ideas for CPL, already from the critique of ALGOL 60 [Stra61], which influenced the languages of the Edinburgh program, was recursion annotation. In its final and most popular form, it uses the keywords `rec` and `and`.
|
||||
For ALGOL 60 such annotations were considered but rejected by a small margin [Naur78].
|
||||
|
||||
###### отсутствие аннотаций рекурсии
|
||||
###### absence of recursion annotations
|
||||
|
||||
Не смотря на то, что Стрейчи критиковал ALGOL 60 за отсутствие аннотаций рекурсии, в работах, в которых "CPL" используется как псевдокод, он эти аннотации обычно пропускал [Stra66].
|
||||
Так что не важно, есть в вашем ФЯ аннотация рекурсии или нет - избежать влияния CPL не удалось. Как и влияния ALGOL 60, разумеется.
|
||||
Although Strachey criticized ALGOL 60 for the absence of recursion annotations, in works where "CPL" is used as pseudocode he usually omitted those annotations [Stra66].
|
||||
So it does not matter whether your functional language has recursion annotations or not - avoiding CPL's influence was not possible. Neither was avoiding ALGOL 60's influence, of course.
|
||||
|
||||
###### отсутствие аннотаций типов
|
||||
###### absence of type annotations
|
||||
|
||||
Не аннотировать типы в псевдокоде легко, в имплементированном языке уже сложнее. Самое сложное, конечно, когда типы есть и их не надо аннотировать, но можно сделать и проще, если аннотировать нечего или если замести аннотации куда-нибудь не на очень видное место. В каждом из трех первоначальных языков Эдинбургской программы будет один из трех основных способов: хороший, плохой и отвратительный.
|
||||
Not annotating types in pseudocode is easy; in an implemented language it is harder. The hardest case, of course, is when types exist and you do not have to annotate them, but you can also make things easier if there is nothing to annotate or if you hide annotations somewhere not very visible. In each of the three original languages of the Edinburgh program there will be one of the three main approaches: good, bad, and ugly.
|
||||
|
||||
###### обозначение блоков отступами
|
||||
###### block delimiting by indentation
|
||||
|
||||
В ISWIM [Land64] [Land65a]
|
||||
In ISWIM [Land64] [Land65a]
|
||||
|
||||
```haskell
|
||||
let x = M; L
|
||||
|
|
@ -503,49 +502,49 @@ let x = M
|
|||
L
|
||||
```
|
||||
|
||||
###### "одновременные"/"параллельные" декларации
|
||||
###### "simultaneous"/"parallel" declarations
|
||||
|
||||
Зачатки паттерн-матчинга, пока без вложений и ветвлений.
|
||||
The beginnings of pattern matching, still without nesting or branching.
|
||||
|
||||
В ISWIM [Land64]
|
||||
In ISWIM [Land64]
|
||||
|
||||
```
|
||||
(u,v) = (2*p + q, p - 2*q)
|
||||
```
|
||||
|
||||
В псевдоCPL [Stra66] и ISWIM 65 [Land65b]
|
||||
In pseudoCPL [Stra66] and ISWIM 65 [Land65b]
|
||||
|
||||
```haskell
|
||||
let u, v = 2*p + q, p - 2*q
|
||||
```
|
||||
|
||||
##### обсуждавшиеся фичи
|
||||
##### Discussed Features
|
||||
|
||||
За считанные месяцы до окончательного прекращения всех работ по CPL Стрейчи делает доклад [Stra67] в котором рассуждает о системе типов, о полиморфизме и различиях между параметрическим и ad-hoc, о том как, возможно, будут сделаны составные типы и что будет, возможно, решено делать ли в CPL параметрические типы и если да, то как. Никто это не решал и не имплементировал, но, благодаря этим анонсам и рассуждениям, Стрейчи стали считать одним из изобретателей полиморфизма.
|
||||
Just months before the final cessation of all work on CPL, Strachey gave a talk [Stra67] in which he reasoned about type systems, about polymorphism and the differences between parametric and ad hoc, about how composite types might be done, and whether CPL would decide to have parametric types and if so, how. No one decided this and no one implemented it, but thanks to these announcements and reflections, Strachey came to be considered one of the inventors of polymorphism.
|
||||
|
||||
###### параметрический полиморфизм
|
||||
###### Parametric Polymorphism
|
||||
|
||||
В докладе Стрейчи наконец-то представляет тип всех тех псевдокодовых `map` [Stra67]:
|
||||
In the talk, Strachey finally presents the type of all those pseudocode `map`s [Stra67]:
|
||||
|
||||
```
|
||||
(α ⇒ β, α list) ⇒ β list
|
||||
```
|
||||
|
||||
Лекции были опубликованы только в 2000 году, так что префиксная форма полиморфных типов может быть более поздней нотацией "как в ML". Но, по видимому, происходит от постфиксных аннотаций вроде `string ref`, которые были имплементированы [Coul68] и вероятно происходят от типов из ALGOL 60. Таких как `integer array`.
|
||||
В типизированном ISWIM Берджа [Burg64] эта сигнатура выглядела бы
|
||||
The lectures were published only in 2000, so the prefix form of polymorphic types may be a later notation "as in ML." But it apparently comes from postfix annotations like `string ref`, which were implemented [Coul68] and likely descend from ALGOL 60 types such as `integer array`.
|
||||
In Burge's typed ISWIM [Burg64] this signature would look like
|
||||
|
||||
```
|
||||
map ∈ (A -> B) -> (A-list -> B-list)
|
||||
```
|
||||
|
||||
но именно такой сигнатуры мы в его работах не видели.
|
||||
Эдинбуржцы ссылаются на работу Стрейчи по полиморфизму [Miln78], но в такой тривиальной форме идея параметрического полиморфизма была, по всей видимости, переоткрыта независимо. Например авторами языка CLU, на который эдинбуржцы также ссылаются. Возможно, переоткрыта даже в рамках Обоекембриджской программы.
|
||||
Интересно, что автор языка CLU Барбара Лисков (Barbara Liskov) пишет [Lisk93], что параметризованные типы в CLU появились из идеи сделать пользовательские типы вроде упомянутых уже выше массивов или функций ALGOL 60. Т.е. как очевидный шаг, которому не уделяется особого внимания в статьях по CLU и его истории. В отличие от ограниченного "интерфейсами" параметрического полиморфизма, который описывается как интересная и сложная идея и проблема, потребовавшая долгие годы для дизайна и имплементации.
|
||||
И для интересных проблем, касающихся полиморфизма, от обоекембриджцев решений эдинбуржцам не осталось.
|
||||
but we did not see exactly such a signature in his works.
|
||||
The Edinburgh researchers refer to Strachey's work on polymorphism [Miln78], but in such a trivial form the idea of parametric polymorphism was apparently reinvented independently. For example by the authors of the CLU language, which the Edinburgh researchers also cite. Possibly it was reinvented even within the two-Cambridge program.
|
||||
Interestingly, the author of CLU, Barbara Liskov, writes [Lisk93] that parameterized types in CLU arose from the idea of making user-defined types such as the arrays or functions of ALGOL 60 mentioned above. That is, as an obvious step that receives little attention in papers on CLU and its history. In contrast to the parametric polymorphism constrained by "interfaces," which is described as an interesting and difficult idea and problem that required many years of design and implementation.
|
||||
And for interesting problems related to polymorphism, the two-Cambridge researchers left no solutions for the Edinburgh researchers.
|
||||
|
||||
###### Изобрел ли Ландин АлгТД?
|
||||
###### Did Landin Invent ADTs?
|
||||
|
||||
Тернер утверждает, что да [Turn12], и на первый взгляд он прав. Уже в статье [Land64] 64-го года и, вероятно, в лекциях для летней школы 63-го года [Fox66] Ландин использует неформальную нотацию для определения структур данных:
|
||||
Turner claims yes [Turn12], and at first glance he is right. Already in the 1964 paper [Land64] and, probably, in the 1963 summer school lectures [Fox66], Landin uses an informal notation for defining data structures:
|
||||
|
||||
```
|
||||
A list is either null
|
||||
|
|
@ -553,7 +552,7 @@ A list is either null
|
|||
and a tail (t) which is a list.
|
||||
```
|
||||
|
||||
Описание у Ландина достаточно неформальное, чтоб не связываться с проблемами не изобретенного еще как следует полиморфизма и вообще избегать указывать что представляет из себя поле `head` (`h` там не параметр, а сокращенное имя поля). Бердж описывает список как параметрический [Burg64], или, может быть, как конвенцию по именованию списков
|
||||
Landin's description is informal enough to avoid dealing with the problems of polymorphism not yet properly invented, and to avoid specifying what the `head` field actually is (`h` there is not a parameter, but an abbreviated field name). Burge describes the list as parametric [Burg64], or perhaps as a naming convention for lists
|
||||
|
||||
```
|
||||
An A-list is either null and is a nullist
|
||||
|
|
@ -561,7 +560,7 @@ or has a head (or h) which is an A and a tail
|
|||
(or t) which is an A-list
|
||||
```
|
||||
|
||||
Если на первый взгляд Тернер прав, то на второй и следующие взгляды сходство уже не так очевидно. Такая декларация объявляет не конструкторы АлгТД, которые могут использоваться и как паттерны. Паттерн-матчинга в ISWIM еще нет. Декларация объявляет предикаты и селекторы, имена которых указывает программист, а также конструкторы, имена которых формируются по правилам из имен предикатов и имени всей структуры:
|
||||
If at first glance Turner is right, then on second and subsequent looks the similarity is not so obvious. Such a declaration does not declare the constructors of ADTs, which can also be used as patterns. There is no pattern matching in ISWIM yet. The declaration defines predicates and selectors whose names are specified by the programmer, as well as constructors whose names are formed by rules from the predicate names and the name of the whole structure:
|
||||
|
||||
```
|
||||
null(constructnullist()) = true
|
||||
|
|
@ -570,9 +569,9 @@ h(constructlist(x, L)) = x
|
|||
constructlist(h L, t L) = L
|
||||
```
|
||||
|
||||
В данном случае имя для `cons` вообще не написано (понятно, что такой предикат избыточен, хватит и `null`), но в более поздних статьях списки определены с `cons` [Land66].
|
||||
Ладно, паттерн-матчинга нет, но хотя-бы общая идея сумм произведений-то была изобретена? Вроде бы, со вторым, более узким определением Тернер прав. Идея сумм произведений ясна.
|
||||
Но нам эта идея ясна потому, что мы уже знаем АлгТД как суммы произведений. Посмотрим на более сложную структуру, например описание абстрактного синтаксического дерева ISWIM [Land66]:
|
||||
In this case the name for `cons` is not written at all (obviously such a predicate is redundant; `null` is enough), but in later articles lists are defined with `cons` [Land66].
|
||||
Okay, there is no pattern matching, but was at least the general idea of sums of products invented? With the second, narrower definition, Turner seems to be right. The idea of sums of products is clear.
|
||||
But this idea is clear to us because we already know ADTs as sums of products. Let us look at a more complex structure, for example the description of the ISWIM abstract syntax tree [Land66]:
|
||||
|
||||
```
|
||||
an aexpression (aexp) is
|
||||
|
|
@ -587,8 +586,8 @@ an aexpression (aexp) is
|
|||
or one-armed ...
|
||||
```
|
||||
|
||||
Так, что тут у нас, сумма произведений сумм произведений ...
|
||||
Нотация для псевдокода, для которого пока особо не придумывали как объявлять типы, а декларации АлгТД должны ведь и типы объявлять. И суммы произведений позволяют это удобно делать. А нотация Ландина - не позволяет, по крайней мере в неизменном виде. В современном ФЯ это выглядело бы как-то так:
|
||||
So what do we have here, a sum of products of sums of products ...
|
||||
This is notation for pseudocode, for which they had not yet really figured out how to declare types, while ADT declarations must declare types. Sums of products allow this conveniently. Landin's notation does not, at least not unchanged. In a modern functional language it would look something like this:
|
||||
|
||||
```haskell
|
||||
data AExp
|
||||
|
|
@ -600,9 +599,9 @@ data AExp
|
|||
...
|
||||
```
|
||||
|
||||
Если посмотреть на то что получилось, когда обоекембриджцы попытались перейти от нестрогого описания к чему-то более точному и типизировать это, то тут-то появляются уже серьезные основания сомневаться в том, что суммы произведений уже были изобретены.
|
||||
Отступив от бесконечно вложенных сумм и произведений слишком далеко назад они получили отдельные декларации для произведений и для сумм. Или не отступили, а просто позаимствовали эту систему из другого языка, к которому мы еще вернемся.
|
||||
Ричардс вспоминает, что авторы CPL много обсуждали как сделать композитные типы но так и не остановились ни на чем до того, как он покинул проект [Rich13]. Этот процесс, по всей видимости, не документирован. Известен только конечный результат из того самого доклада Стрейчи [Stra67], в котором он рассказывал про полиморфизм.
|
||||
If we look at what happened when the two-Cambridge researchers tried to move from a loose description to something more precise and to type it, this is where there are serious grounds to doubt that sums of products had already been invented.
|
||||
Backing away too far from infinitely nested sums and products, they ended up with separate declarations for products and for sums. Or they did not back away, but simply borrowed this system from another language, which we will return to.
|
||||
Richards recalls that the CPL authors discussed for a long time how to make composite types but never settled on anything before he left the project [Rich13]. This process is apparently undocumented. Only the final result from that very Strachey talk [Stra67], in which he spoke about polymorphism, is known.
|
||||
|
||||
```
|
||||
node Cons is LispList : Car
|
||||
|
|
@ -616,69 +615,69 @@ element LispList is Atom
|
|||
|
||||
```
|
||||
|
||||
(да, тип и имя поля на неправильных сторонах `:`)
|
||||
(yes, the type and the field name are on the wrong sides of `:`)
|
||||
|
||||
Декларация вводит три новых типа `Cons`, `Atom` и `LispList`
|
||||
и их конструкторы с селекторами.
|
||||
`element` объявляет не тип сумму, а или-тип, конструктор `LispList` перегружен, параметр может принимать и объекты типа `Atom` и `Cons`. Тип, а не имя конструктора определяет что за значение конструируется.
|
||||
Конструктор для пустого списка не определен потому, что в этом пропозале для CPL есть специальные конструктор `NIL` и предикат `Null`. Да, для того чтоб делать то, что обожают делать в мейнстримных языках, а вот в ФЯ Эдинбургской программы - не особенно.
|
||||
Схожая "одноуровневая" система будет и в ISWIM. Далее мы увидим, что один из изобретателей ПМ по АлгТД уже в Эдинбурге понимал типизированную версию Ландинской нотации так же, как и авторы CPL.
|
||||
The declaration introduces three new types, `Cons`, `Atom`, and `LispList`,
|
||||
and their constructors with selectors.
|
||||
`element` declares not a sum type but an either-type; the constructor `LispList` is overloaded, its parameter can take objects of both type `Atom` and `Cons`. The type, not the constructor name, determines what value is constructed.
|
||||
The constructor for the empty list is not defined because in this CPL proposal there is a special constructor `NIL` and predicate `Null`. Yes, for doing what mainstream languages love to do, but not so much in the functional languages of the Edinburgh program.
|
||||
A similar "single-level" system will also be in ISWIM. Later we will see that one of the inventors of pattern matching for ADTs already in Edinburgh understood the typed version of Landin's notation in the same way as the CPL authors.
|
||||
|
||||
### Следующие 700 не самых быстрых имплементаций
|
||||
### The Next 700 Not-So-Fast Implementations
|
||||
|
||||
> Мы здесь рассматриваем возможность, а не практичность. Тем не менее, то, что написано ниже, может быть принято за отправную точку для разработки эффективной имплементации.
|
||||
> Питер Ландин, ЛИ подход [Land66b]
|
||||
> We are considering possibility here, not practicality. Nevertheless, what is written below may be taken as a starting point for developing an efficient implementation.
|
||||
> Peter Landin, The lambda calculus approach [Land66b]
|
||||
|
||||
Основная литература по имплементации ФЯ от обоекембриджской программы осталась от ISWIM - языка спецификации, который предполагалось "выполнять" с помощью ручки и бумаги. Это ставило реальную цель. Цель была достигнута и первые доклады сделаны Ландином в 63-ем и статья опубликована в 64-ом [Land64].
|
||||
CPL был амбициозной попыткой имплементировать ФЯ общего назначения, но имплементация функциональной части не особенно продвинулась.
|
||||
Про имплементацию CPL в Кембридже мало что опубликовано. Раз уж попытка закончилась неудачей, публиковать было нечего.
|
||||
Мы бы не хотели создать впечатление, что цель Ландина была скромной, или что ее достижение было незначительным результатом. Цель была просто реалистичнее, чем цель CPL-щиков. Которые планировали имплементировать за два года ФЯ не только на самом этом ФЯ, но и как единственный язык для новой машины. Единственный потому, что должен был подходить для любых задач.
|
||||
Сомнительно, что такую цель кто-то достиг бы и сегодня, при том, что мы знаем как делать ФЯ. А в 62-ом не знал никто. Но, правда, были уже две школы ФЯ-строения, которые либо не знали, что они не знают, либо не очень и хотели делать ФЯ. Причем не знали/не хотели они разные вещи. К этим направлениям недо-ФП-мысли мы вернемся позже.
|
||||
Ландин всего-навсего был первым, кто придумал работающую идею. Вернее потенциально работающую. В предисловии мы определили практическую имплементацию как компилятор, способный компилировать хотя-бы компилятор ФЯ или что-то схожее по сложности. И наработки Ландина никогда не достигли этого уровня практичности. Но базирующиеся на них - достигли.
|
||||
До Ландина механизация вычисления лямбда-выражений, которые действительно вычисляются как лямбда-выражения, была только в форме переписывания последовательностей символов или деревьев, как, например, оптимизатор компилятора переписывает код [Gilm63].
|
||||
Ландин описал стековую машину, что гораздо практичнее, но не без проблем.
|
||||
Стековая машина - это то, что до Ландина уже позволяло имплементировать язык с рекурсивными функциями [Dijk60] первого порядка, и даже решить половину проблем с функциями высшего порядка, а именно передавать функции в функции [Rand64].
|
||||
Оставалось решить проблему с возвращением функций из функций.
|
||||
Для этого Ландин использовал замыкания, сам термин введен им. Он, правда, не изобрел замыкание как структуру данных. Похожие структуры из ссылки на функцию и полей для её свободных переменных использовались, только на стеке, для имплементации передачи аргументов по имени в ALGOL 60 и назывались PARD [Dijk62]. Ландин применил их для возврата функций из функций, аллоцируя в куче со сборщиком мусора, который к тому времени уже применили в Лиспе [McCa60].
|
||||
У Ландина получилась машина с четырьмя регистрами, названная SECD по именам регистров: Stack, Environment, Control, Dump.
|
||||
C - программа, список аппликативных выражений, которые машина редуцирует.
|
||||
S - стек, нужен для имплементации функций.
|
||||
D - хранит снапшот полного состояния машины (S,E,C,D) и нужен для имплементации лямбд.
|
||||
E - окружение. Нужно для того, чтоб у лямбд могли быть свободные переменные.
|
||||
Первая опубликованная версия SECD-машины имплементировала лямбда-исчисление, в которое транслировалась чисто функциональная версия ISWIM [Land64].
|
||||
В 64-ом Ландин расширил язык, добавив к ЛИ присваивание и операцию захвата продолжения. Это расширенное ЛИ он назвал IAE - императивные аппликативные выражения, а новую версию SECD-машины - sharing machine [Land65a]. Для имплементации захвата продолжения в этой машине добавлена еще одна разновидность замыкания "программа-замыкание", которое добавляет к функции не только окружение E, но все состояние машины D.
|
||||
Версия статьи про SECD [Land64] 66-го года в сборнике [Fox66] уделяла больше внимания имплементации SECD с помощью компьютера, а не ручки и бумаги [Land66b].
|
||||
Понятно, что имплементация рекурсии с помощью стека - не самый практичный способ имплементировать ФЯ. Обязательное использование сборщика мусора, практичной имплементации которого еще не существовало, было даже большей проблемой. Но эти проблемы были решаемы, и были решены позже, что мы в дальнейшем рассмотрим подробнее.
|
||||
Пытались ли имплементаторы CPL использовать идеи Ландина? В воспоминаниях участников упоминается, что для имплементации используются "аппликативные выражения" [Camp85] как у Ландина. Но это скорее всего не означает трансляции в лямбда-исчисление. В описании имплементации нефункционального языка BCPL [Rich69] тоже говорится об аппликативных выражениях, но в данном случае это точно не лямбда - просто промежуточное представление в виде дерева.
|
||||
Во время работы в Univac Ландин и Уильям Бердж имплементировали прототип SECD [Land66] для Univac 1107 [Burg64]. Эта попытка имплементации по всей видимости не была успешной, потому что от нее осталось только пара упоминаний в статьях и перечне документов из личного архива Ландина [Landin].
|
||||
И Ландин и Бердж предпримут еще по одной попытке, но уже не в Univac.
|
||||
The main literature on functional-language implementation from the two-Cambridge program remained with ISWIM - a specification language intended to be "executed" with pen and paper. This set a real goal. The goal was achieved, and the first reports were made by Landin in 1963 and the paper published in 1964 [Land64].
|
||||
CPL was an ambitious attempt to implement a general-purpose functional language, but the implementation of its functional part did not advance much.
|
||||
Little was published about the CPL implementation in Cambridge. Since the attempt ended in failure, there was nothing to publish.
|
||||
We would not like to give the impression that Landin's goal was modest or that its achievement was an insignificant result. The goal was simply more realistic than the goal of the CPL group, who planned to implement in two years a functional language not only in that functional language itself, but also as the only language for a new machine. The only language because it was supposed to fit any task.
|
||||
It is doubtful that anyone would achieve such a goal even today, given that we know how to make functional languages. In 1962, no one knew. But there were already two schools of functional-language building that either did not know that they did not know, or did not really want to make functional languages. And what they did not know or did not want was different. We will return to these directions of pseudo-FP thought later.
|
||||
Landin was simply the first to come up with a working idea. Rather, a potentially working one. In the preface we defined a practical implementation as a compiler capable of compiling at least a compiler for a functional language or something similar in complexity. Landin's work never reached that level of practicality. But those based on it did.
|
||||
Before Landin, the mechanization of evaluating lambda expressions that actually evaluate as lambda expressions existed only in the form of rewriting sequences of symbols or trees, as, for example, a compiler optimizer rewrites code [Gilm63].
|
||||
Landin described a stack machine, which is much more practical, but not without problems.
|
||||
A stack machine is what, before Landin, already allowed implementing a language with first-order recursive functions [Dijk60], and even solving half the problems with higher-order functions, namely passing functions to functions [Rand64].
|
||||
It remained to solve the problem of returning functions from functions.
|
||||
For this, Landin used closures, a term he introduced himself. He did not, however, invent the closure as a data structure. Similar structures consisting of a reference to a function and fields for its free variables were used, only on the stack, to implement call-by-name argument passing in ALGOL 60 and were called PARD [Dijk62]. Landin used them to return functions from functions, allocating them on the heap with garbage collection, which by then had already been used in Lisp [McCa60].
|
||||
Landin ended up with a machine with four registers, named SECD after the registers: Stack, Environment, Control, Dump.
|
||||
C - the program, a list of applicative expressions that the machine reduces.
|
||||
S - the stack, needed for implementing functions.
|
||||
D - stores a snapshot of the full machine state (S,E,C,D) and is needed for implementing lambdas.
|
||||
E - the environment. It is needed so that lambdas can have free variables.
|
||||
The first published version of the SECD machine implemented the lambda calculus, into which the purely functional version of ISWIM was translated [Land64].
|
||||
In 1964 Landin extended the language by adding assignment and a continuation-capture operation to the lambda calculus. He called this extended lambda calculus IAE - imperative applicative expressions - and the new version of the SECD machine the sharing machine [Land65a]. To implement continuation capture, this machine adds another kind of closure, a "program closure," which adds to the function not only the environment E but the entire machine state D.
|
||||
The 1966 version of the SECD paper [Land64] in the collection [Fox66] paid more attention to implementing the SECD with a computer rather than with pen and paper [Land66b].
|
||||
It is clear that implementing recursion with a stack is not the most practical way to implement a functional language. The mandatory use of garbage collection, for which a practical implementation did not yet exist, was an even bigger problem. But these problems were solvable, and were solved later, which we will consider in more detail.
|
||||
Did CPL implementers try to use Landin's ideas? The recollections of participants mention that "applicative expressions" were used for implementation [Camp85], as in Landin. But this most likely does not mean translation into lambda calculus. The description of the implementation of the non-functional language BCPL [Rich69] also speaks of applicative expressions, but in that case it is definitely not lambda - just an intermediate representation as a tree.
|
||||
While working at Univac, Landin and William Burge implemented a SECD prototype [Land66] for the Univac 1107 [Burg64]. This implementation attempt was apparently not successful, because only a couple of mentions of it remain in papers and in the list of documents from Landin's personal archive [Landin].
|
||||
Both Landin and Burge would make one more attempt each, but no longer at Univac.
|
||||
|
||||
В другом Кембридже
|
||||
In the Other Cambridge
|
||||
------------------
|
||||
|
||||
Возможно, что вклад CPL в историю языков программирования пока не выглядит выдающимся. Но, как это не удивительно, уже описанного хватило для того, чтоб впечатлить некоторых участников Эдинбургской исследовательской программы. Чтобы впечатлить остальных, а сверх того, еще и сделать CPL непосредственным предком многих популярных современных языков, понадобились еще и труды исследователей и имплементаторов в другом Кембридже. Точнее, в основном, одного имплементатора - Мартина Ричардса.
|
||||
Perhaps CPL's contribution to the history of programming languages does not yet look outstanding. But, surprisingly, what has been described so far was enough to impress some participants of the Edinburgh research program. To impress the rest, and in addition to make CPL a direct ancestor of many popular modern languages, it also took the work of researchers and implementers in the other Cambridge. More precisely, mostly one implementer - Martin Richards.
|
||||
|
||||
### Мартин Ричардс
|
||||
### Martin Richards
|
||||
|
||||
Мартин Ричардс (Martin Richards) с 1959 изучал математику в том самом Кембридже. В октябре 1963 он приступил к работе над диссертацией, повстречался со Стрейчи, и его затянуло в CPL проект [Comp17]. Стрейчи не мог быть его научруком официально, и им стал Баррон, а после того, как тот потерял интерес к CPL через год - Дэвид Парк [Rich2000], интересы которого тоже со временем поменялись.
|
||||
Три года, до декабря 1966, Ричардс был практически единственным человеком в Кембридже работавшем только над CPL, занимаясь имплементацией его минимального подмножества Basic CPL, фактически виртуальной машины, которое должно было быть использовано для имплементации полнофункционального компилятора. Который, как мы помним, не имплементировали.
|
||||
Вырвавшись из трясины обреченного проекта, которым никто кроме него не занимался, Ричардс отправился в МТИ.
|
||||
Перед этим он заверил Стрейчи, что уж там-то он развернет работу над имплементацией CPL по настоящему.
|
||||
Или, по крайней мере, Стрейчи заверял что план был именно такой [Strachey]. Еще осенью 67-го он рассказывал в докладе [Stra67], что портабельный компилятор CPL скоро будет готов.
|
||||
Казалось бы, после того как, брошенный своими научруками, Ричардс провалил написание кембриджского компилятора, можно ли было ждать от него успехов в МТИ? Но успехи не заставили себя ждать.
|
||||
Martin Richards studied mathematics in that very Cambridge starting in 1959. In October 1963 he began work on his dissertation, met Strachey, and was drawn into the CPL project [Comp17]. Strachey could not be his official supervisor, so Barron became one; after Barron lost interest in CPL a year later, David Park took over [Rich2000], whose interests also changed over time.
|
||||
For three years, until December 1966, Richards was practically the only person in Cambridge working solely on CPL, implementing its minimal subset Basic CPL, effectively a virtual machine intended to be used to implement a full compiler. Which, as we remember, was never implemented.
|
||||
Escaping the mire of a doomed project that no one but him was working on, Richards went to MIT.
|
||||
Before that he assured Strachey that there he would really ramp up work on implementing CPL.
|
||||
Or at least Strachey assured that this was the plan [Strachey]. As late as fall 1967 he said in a talk [Stra67] that a portable CPL compiler would soon be ready.
|
||||
One might think that after being abandoned by his supervisors, Richards had failed to write the Cambridge compiler, and there could be no success at MIT. But the successes were not long in coming.
|
||||
|
||||
### BCPL
|
||||
|
||||
> BCPL - это просто CPL из которого удалены все сложные части.
|
||||
> Мартин Ричардс, Как BCPL эволюционировал из CPL [Rich13]
|
||||
> BCPL is just CPL with all the complex parts removed.
|
||||
> Martin Richards, How BCPL evolved from CPL [Rich13]
|
||||
|
||||
> Ряд синтаксических и лексических механизмов BCPL элегантнее и последовательнее, чем в B и C.
|
||||
> Деннис Ритчи, позаботившийся об этом [Ritc93]
|
||||
> A number of BCPL's syntactic and lexical mechanisms are more elegant and consistent than in B and C.
|
||||
> Dennis Ritchie, who saw to that [Ritc93]
|
||||
|
||||
В МТИ Ричардс работал вместе с Ландиным под началом Джона Возенкрафта (John "Jack" Wozencraft) [Rich2000] с декабря 66-го по октябрь 68-го. [Rich2000] [Comp17]
|
||||
В МТИ Ричардс написал компилятор Basic CPL на AED-0 [Rich2000], похожем на ALGOL 60 языке, но с указателями и прочими фичами для системного программирования [Ross61]. Затем он написал компилятор BCPL на BCPL. Начальная версия компилятора в 1K строк была готова в начале 67-го года [Rich2000] для CTSS на IBM 7094 [Rich13]. За следующие 10 лет компилятор вырос до 5K строк и еще столько же строк тулинга вроде отладчика и редактора [Atki78].
|
||||
Получившийся язык не был уже минимальным подмножеством CPL или ВМ для его имплементации. Это был достаточно большой язык со многими фичами позволяющими делать одно и то же разными способами - управляющими структурами и т.д. [Rich74], который сам использовал стековую виртуальную машину Ocode для удобства портирования компилятора [Rich69]. BCPL отличался от CPL тем, что все что в CPL было сложно имплементировать в BCPL не попало.
|
||||
И все что нам, как историкам ФП, интересно - было сложно имплементировать. Понятно, что в BCPL нельзя было вернуть замыкание, и, соответственно, не требовался сборщик мусора. Но даже ограниченной ФП-функциональности ALGOL с передачей замыкания вниз по стеку не было. Свободные переменные могли быть только статическими [Rich74]:
|
||||
At MIT, Richards worked with Landin under John "Jack" Wozencraft [Rich2000] from December 1966 to October 1968 [Rich2000] [Comp17].
|
||||
At MIT Richards wrote a Basic CPL compiler in AED-0 [Rich2000], a language similar to ALGOL 60 but with pointers and other system-programming features [Ross61]. He then wrote a BCPL compiler in BCPL. The initial 1K-line compiler was ready in early 1967 [Rich2000] for CTSS on the IBM 7094 [Rich13]. Over the next 10 years the compiler grew to 5K lines and another 5K lines of tooling such as a debugger and editor [Atki78].
|
||||
The resulting language was no longer a minimal subset of CPL or a VM for its implementation. It was a fairly large language with many features that allowed doing the same thing in different ways - control structures and so on [Rich74] - and it used a stack virtual machine, Ocode, to make the compiler easier to port [Rich69]. BCPL differed from CPL in that everything that was hard to implement in CPL did not make it into BCPL.
|
||||
And everything that is interesting to us as FP historians was hard to implement. It is clear that in BCPL you could not return a closure, and therefore no garbage collector was required. But even the limited FP functionality of ALGOL with passing a closure down the stack was absent. Free variables could only be static [Rich74]:
|
||||
|
||||
```f#
|
||||
let a, b = 1, 2
|
||||
|
|
@ -692,24 +691,24 @@ static $( a = 1; b = 2 $)
|
|||
let f (x) = a*x + b
|
||||
```
|
||||
|
||||
Ричардс оставил в BCPL один тип - слово. Не стал имплементировать выражение `where`, опередив на четверть века моду на выкидывание выражения `where` из ФЯ. Убрал аннотации рекурсии.
|
||||
Не смотря на все эти урезания, BCPL все равно сложный язык, со вложенными функциями, возвращающими значения блоками-выражениями. Компилятор BCPL строил абстрактное синтаксическое дерево [Rich69] и потому имел серьезные для того времени требованиями к памяти. Поэтому Кен Томпсон не мог его использовать на той машине, на которой писал Unix и сделал еще более урезанную версию языка без всех этих вложенностей: B [Ritc93]. Томпсон сделал и некоторые изменения не связанные с экономией памяти. B - один из ранних примеров декембриджизации. Это процесс изменения синтаксиса происходящего от обоекембриджской ветви на любой другой, лишь бы только иначе выглядящий, широко практиковался в наши дни авторами Scala, Rust, Swift и др.
|
||||
От B произошел C и далее большая часть ЯП-мейнстрима, каким мы его знаем и любим.
|
||||
Сам BCPL использовался до 80-х годов. В том числе и некоторыми имплементаторами ФЯ.
|
||||
В апреле 68-го Стрейчи получил письмо от Ричардса о том, что тот передумал имплементировать CPL, а решил вместо этого дальше развивать BCPL [Strachey].
|
||||
Richards left only one type in BCPL - the word. He did not implement the `where` expression, anticipating by a quarter century the fashion of throwing the `where` expression out of functional languages. He removed recursion annotations.
|
||||
Despite all these cuts, BCPL is still a complex language, with nested functions and value-returning block expressions. The BCPL compiler built an abstract syntax tree [Rich69] and therefore had serious memory requirements for its time. Therefore Ken Thompson could not use it on the machine on which he wrote Unix and made an even more stripped-down version of the language without all these nestings: B [Ritc93]. Thompson also made some changes not related to saving memory. B is one of the early examples of decambridgization - the process of changing the syntax descended from the two-Cambridge branch into something else, anything that just looks different, widely practiced today by the authors of Scala, Rust, Swift, and others.
|
||||
From B came C and then most of the mainstream programming languages as we know and love them.
|
||||
BCPL itself was used until the 1980s, including by some functional-language implementers.
|
||||
In April 1968 Strachey received a letter from Richards saying that he had changed his mind about implementing CPL and decided to continue developing BCPL instead [Strachey].
|
||||
|
||||
### PAL
|
||||
|
||||
> Поскольку никто не пишет реальные программы на PAL, мы можем позволить себе неэффективную имплементацию, которая иначе была бы неприемлемой.
|
||||
> Артур Эванс, PAL - язык, спроектированный для преподавания. [Evan68]
|
||||
> Since no one writes real programs in PAL, we can afford an inefficient implementation that would otherwise be unacceptable.
|
||||
> Arthur Evans, PAL - a language designed for teaching [Evan68]
|
||||
|
||||
Создав первый практический (он же первый нефункциональный) язык обоекембриджской программы, Ричардс не остановился на достигнутом и приступил к имплементации функционального языка с ограниченной практичностью.
|
||||
Этим языком ограниченной практичности был PAL - педагогический алгоритмический язык [Evan68b], разрабатываемый специально для курса 6.231 МТИ "Programming Linguistics".
|
||||
Первыми его имплементаторами были теперь работающий в МТИ Ландин и Джеймс Моррис (James H. Morris, Jr.). Они написали на Лиспе то, что конечно же было ISWIM-ом с незначительными изменениями. Но имплементация, видимо, получилась слишком непрактичной даже для языка, непрактичность которого пытались представить как фичу, позволяющую ему имплементировать всякие сумасшедшие вещи вроде лямбда-исчисления. Поэтому вторую версию в 68 году имплементировали Мартин Ричардс и Томас Баркалоу (Thomas J. Barkalow) на BCPL для IBM 7094 под CTSS. Компилятор в байт-код к 70-му году был 1.3KLOC, а интерпретатор 1.5KLOC.
|
||||
PAL имплементирован с помощью SECD машины, которую авторы PAL почему-то называют CSED-машиной.
|
||||
Проблема неуказывания типов в псевдокодах решена тем, что язык "динамически" типизирован.
|
||||
Описывающие PAL говорят, что вторая имплементация отличалась от ISWIM несколько больше [Evan68] [Rich13], но не говорят чем.
|
||||
Мы рискнем предположить, что это за отличие, тем более, что это отличие практически единственное заметное: в ISWIM добавили лямбду.
|
||||
Having created the first practical (and also the first non-functional) language of the two-Cambridge program, Richards did not stop there and moved on to implementing a functional language with limited practicality.
|
||||
That limited-practicality language was PAL, a pedagogical algorithmic language [Evan68b] developed specifically for MIT course 6.231 "Programming Linguistics."
|
||||
Its first implementers were Landin, now working at MIT, and James H. Morris, Jr. They wrote in Lisp what was, of course, ISWIM with minor changes. But the implementation apparently turned out to be too impractical even for a language whose impracticality was presented as a feature, allowing it to implement crazy things like the lambda calculus. Therefore, in 1968 the second version was implemented by Martin Richards and Thomas J. Barkalow in BCPL for the IBM 7094 under CTSS. By 1970 the bytecode compiler was 1.3 KLOC and the interpreter 1.5 KLOC.
|
||||
PAL was implemented with the SECD machine, which the PAL authors for some reason call the CSED machine.
|
||||
The problem of not specifying types in pseudocode was solved by making the language "dynamically" typed.
|
||||
Those describing PAL say that the second implementation differed from ISWIM somewhat more [Evan68] [Rich13], but they do not say how.
|
||||
We will venture to guess what the difference was, especially since this difference is practically the only noticeable one: a lambda was added to ISWIM.
|
||||
|
||||
```haskell
|
||||
def rec map f L = Null L -> nil
|
||||
|
|
@ -718,8 +717,8 @@ def rec map f L = Null L -> nil
|
|||
map (ll x. x + y) (1, (2, (3, nil))) where y = 1
|
||||
```
|
||||
|
||||
Имплементация поддерживалась до 70-го года и язык несущественно менялся.
|
||||
С 69-го он выглядел так [Woze71]:
|
||||
The implementation was maintained until 1970 and the language changed only insignificantly.
|
||||
From 1969 it looked like this [Woze71]:
|
||||
|
||||
```haskell
|
||||
def rec map f L = Null L -> nil
|
||||
|
|
@ -728,10 +727,10 @@ def rec map f L = Null L -> nil
|
|||
map (fn x. x + y) (1, (2, (3, nil))) where y = 1
|
||||
```
|
||||
|
||||
Помимо уже перечисленных имплементаторов, в авторы языка записаны Артур Эванс (Arthur Evans), который написал большую часть статей, репортов и мануалов, Роберт Грэм (Robert M. Graham) и Джон Возенкрафт. Просто поразительно, конечно, сколько авторов может быть у идеи добавить лямбду в функциональный язык.
|
||||
Следующая по очевидности, после добавления лямбды в ФЯ, идея, которая пришла бы в голову современному человеку, конечно, такая: у нас есть непрактичный, медленный ФЯ PAL и практичный язык на котором он имплементирован BCPL. Что если мы будем "склеивать" в коде PAL-скрипта вызовы быстрых функций, написанных на BCPL? Но нет, никаких следов такого рода идей в 1968 году мы не видели. Такие идеи начнут завоевывать умы только к концу 70-х.
|
||||
В Австралии 90-х годов именно эта идея будет воплощена в жизнь владельцем софтверной компании Lennox Computer Дугласом Ленноксом. Он использует сочетание придуманных и имплементированных им клонов ISWIM/PAL называемого GTL (General Tuple Language), сильно отставшего от своего времени, и C называемого (не тот)D [Lennox]. Это только первый из описываемых нами здесь, но не последний из ряда случаев, когда какой-то ФЯ или его имплементация находят неожиданное продолжение жизни у антиподов.
|
||||
В PAL пытались имплементировать Ландинскую аннотацию для описания структур, со всеми особенностями вроде неограниченной степени вложенности
|
||||
Besides the implementers already listed, the language's authors are given as Arthur Evans, who wrote most of the papers, reports, and manuals, Robert M. Graham, and John Wozencraft. It is remarkable, of course, how many authors an idea can have for adding lambda to a functional language.
|
||||
The next obvious idea, after adding lambda to a functional language, that would come to a modern person's mind is this: we have an impractical, slow functional language, PAL, and a practical language it is implemented in, BCPL. What if we "glue" calls to fast functions written in BCPL into PAL script code? But no, we saw no traces of such ideas in 1968. Such ideas would start to win minds only by the end of the 1970s.
|
||||
In 1990s Australia, this idea would be realized by Douglas Lennox, owner of the software company Lennox Computer. He uses a combination of his invented and implemented ISWIM/PAL clones called GTL (General Tuple Language), badly out of date, and C called (not that)D [Lennox]. This is only the first described here, but not the last in a series of cases where some functional language or its implementation finds an unexpected continuation of life among the antipodes.
|
||||
In PAL they tried to implement Landin's notation for describing structures, with all the features such as unlimited nesting
|
||||
|
||||
```
|
||||
def rec LIST which
|
||||
|
|
@ -740,7 +739,7 @@ def rec LIST which
|
|||
else IsNIL
|
||||
```
|
||||
|
||||
и сложный правил для именования конструкторов и предикатов, которые генерировались по описанию.
|
||||
and complex rules for naming constructors and predicates that were generated from the description.
|
||||
|
||||
```
|
||||
def LIST which is
|
||||
|
|
@ -748,15 +747,15 @@ def LIST which is
|
|||
else IsNIL
|
||||
```
|
||||
|
||||
поскольку тут только один "конструируемый объект" `HEAD also TAIL` именем его тега будет имя всей структуры, т.е. `LIST`, а именем его конструктора `MakeLIST` [Zill70]. Но эта работа не была завершена.
|
||||
На PAL было написано кода не сильно больше, чем псевдокода на ISWIM. Это были в основном учебные интерпретаторы и другие примеры из курса для которого PAL и создавался [Woze71]. Для каких-то других целей он, судя по отсутствию следов, не использовался ни в МТИ, ни где-то еще. На то, что делали в МТИ язык оказал минимальное влияние. Другой Кембридж не принял ФП в этот раз.
|
||||
Имплементация PAL самый старый артефакт в этой истории, для которого сейчас доступен исходный код [PAL360]. Исходный код был доступен с самого начала, как и для многого другого разработанного в МТИ на госденьги и являющегося поэтому общественным достоянием. Кроме того, это был код на языке, компилятор которого был переносим на другие машины и был перенесен. Что было редкостью в то время вообще, и особенно в МТИ, где практически все остальные имплементации языков писали на ассемблере, а потом заново, когда меняли машины. Не смотря на все эти качества которые, казалось бы, делали PAL хорошей платформой для разработки ФЯ, он в качестве такой платформы не использовался.
|
||||
За одним исключением.
|
||||
Как мы помним, Стрейчи после CPL-проекта стал работать в Оксфорде. И там он был научруком у человека, который попытался имплементировать PAL эффективно. Чтоб PAL можно было использовать как язык общего назначения. Это ему не удалось. Не то чтоб ему с тех пор хоть раз удалось эффективно имплементировать ФЯ. Но ФЯ, которые он разработает будут хотеть эффективно имплементировать другие люди и он будет далее одним из главных героев этой истории функционального программирования.
|
||||
since there is only one "constructed object" `HEAD also TAIL`, the name of its tag will be the name of the whole structure, i.e., `LIST`, and the name of its constructor will be `MakeLIST` [Zill70]. But this work was not completed.
|
||||
Not much more code was written in PAL than the pseudocode in ISWIM. These were mostly educational interpreters and other examples from the course for which PAL was created [Woze71]. For any other purposes, judging by the absence of traces, it was not used either at MIT or elsewhere. The language had minimal influence on what was done at MIT. The other Cambridge did not adopt FP this time.
|
||||
The PAL implementation is the oldest artifact in this history for which source code is available today [PAL360]. The source code was available from the beginning, like much other software developed at MIT with government money and therefore in the public domain. In addition, it was code in a language whose compiler was portable to other machines and was ported. This was rare at the time in general, and especially at MIT, where almost all other language implementations were written in assembler and then rewritten when machines changed. Despite all these qualities that might have made PAL a good platform for FP development, it was not used as such a platform.
|
||||
With one exception.
|
||||
As we recall, after the CPL project Strachey went to Oxford. There he supervised a person who tried to implement PAL efficiently so that PAL could be used as a general-purpose language. He failed. It is not that he ever since succeeded in implementing functional languages efficiently. But the functional languages he would develop would be ones other people wanted to implement efficiently, and he would become one of the main heroes of this history of functional programming.
|
||||
|
||||
### McG
|
||||
|
||||
Уильям Бердж, работавший с Ландином в Univac, после этого работал в IBM Research в Йорктаун Хайтс. Там он вместе с Бартом Левенвортом (Burt Leavenworth) в 1968 году имплементировал на основе SECD-машины еще один язык мало отличимый от ISWIM - McG [Emde06] [Burg71]:
|
||||
William Burge, who worked with Landin at Univac, later worked at IBM Research in Yorktown Heights. There, together with Burt Leavenworth, in 1968 he implemented another SECD-based language little different from ISWIM - McG [Emde06] [Burg71]:
|
||||
|
||||
```haskell
|
||||
def rec map f x
|
||||
|
|
@ -766,49 +765,49 @@ def rec map f x
|
|||
let y = 1; let f x = x + y; map f (1,2,3);
|
||||
```
|
||||
|
||||
И вот он-то повлияет на отношение к ФП в Йорктаун Хайтс. И Бердж использует его для ФП исследований в 70-е годы.
|
||||
And it was this language that would influence attitudes toward FP in Yorktown Heights. Burge used it for FP research in the 1970s.
|
||||
|
||||
-------------------
|
||||
|
||||
Пришла пора прощаться с основными действующими лицами обоекембриджской истории. Впереди 70-е годы, такой важной роли в истории ФП они уже играть не будут. Ландин занялся административной работой. Ричардс забросил ФП и сконцентрировался на развитии BCPL. Стрейчи умер.
|
||||
Мы отправляемся на север, в новую основную локацию и знакомимся с новыми главными героями: аспирантом Стрейчи, знакомым Ландина и знакомым знакомого Стрейчи.
|
||||
It is time to say goodbye to the main actors of the two-Cambridge story. The 1970s are ahead, and they will no longer play such an important role in the history of FP. Landin moved into administrative work. Richards abandoned FP and focused on developing BCPL. Strachey died.
|
||||
We are heading north, to a new main location, and meeting new main heroes: Strachey's graduate student, Landin's acquaintance, and the acquaintance of an acquaintance of Strachey.
|
||||
|
||||
Эдинбургская исследовательская программа
|
||||
Edinburgh Research Program
|
||||
========================================
|
||||
|
||||
## От исследовательского программирования к экспериментальному.
|
||||
## From research programming to experimental.
|
||||
|
||||
Мартин ван Эмден как-то раз вычитал в журнале New Scientist сумасшедшую историю. В Эдинбурге некие Бурсталл и Поплстоун бросили вызов МТИ, написали многопользовательскую ОС на собственном языке для интерактивного программирования! И как раз в этом, 1968-ом году в Эдинбурге проходит конференция IFIP. Конференция не по функциональному программированию и даже не по программированию вообще, а по всему что связано с использованием компьютеров. Связано с этим пока не очень много, так что одной конференции достаточно для всего. Ван Эмден пока еще только сдавал программы на Алголе на бумажной ленте, чтоб их когда-нибудь запустили и очень хотел увидеть интерактивное программирование и более продвинутый чем Алгол язык. И Математический Центр Амстердама отправил ван Эмдена на конференцию.
|
||||
Конечно же, на конференции было запланировано демо эдинбургской системы. Только кроме ван Эмдена на него никто не пришел. И демо не состоялось из-за проблем с телефонным соединением. Ну что ж. Тем больше времени у разработчиков чтоб рассказать ван Эмдену о проекте. Путь к этому (частичному) успеху, запустившему Эдинбургский университет в TOP4 центров по разработке ИИ, не был прямым [Emde06].
|
||||
Martin van Emden once read a crazy story in New Scientist. In Edinburgh, certain Burstall and Popplestone challenged MIT and wrote a multi-user OS in their own language for interactive programming! And in that year, 1968, an IFIP conference was held in Edinburgh. The conference was not about functional programming, or even about programming at all, but about everything related to the use of computers. There was not much related to that yet, so one conference was enough for everything. Van Emden was still submitting Algol programs on paper tape to be run someday and very much wanted to see interactive programming and a language more advanced than Algol. The Amsterdam Mathematical Centre sent van Emden to the conference.
|
||||
Of course, a demo of the Edinburgh system was planned for the conference. But apart from van Emden, no one came. And the demo did not take place due to problems with the telephone connection. Oh well. All the more time for the developers to tell van Emden about the project. The path to this (partial) success, which propelled the University of Edinburgh into the top 4 AI development centers, was not straightforward [Emde06].
|
||||
|
||||
### Род Бурсталл
|
||||
### Rod Burstall
|
||||
|
||||
Род Бурсталл (Rodney Martineau Burstall) - физик [Burstall] сначала работавший кем-то вроде тех, кого сейчас называют "квант", а затем программистом [Ryde2002]. Бурсталл как-то раз разговорился с другим покупателем в книжном магазине. Этот другой покупатель - Мервин Прагнелл (Mervyn Pragnell) - организовывал подпольный семинар по логике в Лондоне. Подпольный потому, что что официально Лондонский Университет не имел к нему никакого отношения. На этих семинарах в 61-ом году Бурсталл познакомился с Ландином, а Ландин научил его лямбда-исчислению и функциональному программированию в пабе "Герцог Мальборо".
|
||||
Связи в функциональном подполье не обошлись без последствий. Несколько лет спустя, в 1964-ом году Бурсталлу позвонил некий Дональд Мики (Donald Michie) и предложил работу в "Группе Экспериментального Программирования", или может быть в экспериментальной группе программирования в Эдинбургском университете. Бурсталл согласился.
|
||||
Вскоре выяснилось, что кандидатуры рекомендовал Стрейчи, имея в виду, что первые месяцы будущий сотрудник будет работать у него над CPL [Burs2000], тем более, что у экспериментальной группы пока что не было компьютера, так что экспериментальное программирование в ней откладывалось.
|
||||
Работа Бурсталла над CPL, как это обычно бывало с работой над CPL, не имела особо хороших последствий для CPL. Но прежде чем отправиться работать над CPL в октябре 65-го, Бурсталл познакомился со своим коллегой Поплстоуном.
|
||||
Rodney Martineau Burstall was a physicist [Burstall] who first worked as something like what we now call a "quant," and then as a programmer [Ryde2002]. Burstall once struck up a conversation with another buyer in a bookshop. The other buyer, Mervyn Pragnell, organized an underground logic seminar in London. Underground because officially the University of London had nothing to do with it. At these seminars in 1961 Burstall met Landin, and Landin taught him lambda calculus and functional programming in the Duke of Marlborough pub.
|
||||
Connections in the functional underground did not come without consequences. Several years later, in 1964, Donald Michie called Burstall and offered him a job in the "Experimental Programming Group," or perhaps the experimental programming group at the University of Edinburgh. Burstall agreed.
|
||||
It soon turned out that the candidature had been recommended by Strachey, with the idea that the new staff member would spend the first months working with him on CPL [Burs2000], especially since the experimental group did not yet have a computer, so experimental programming there was postponed.
|
||||
Burstall's work on CPL, as was often the case with work on CPL, did not have particularly good consequences for CPL. But before going to work on CPL in October 1965, Burstall met his colleague Popplestone.
|
||||
|
||||
### Робин Поплстоун
|
||||
### Robin Popplestone
|
||||
|
||||
Робин Поплстоун (Robin John Popplestone) - математик, увлекшийся программированием после того, как впервые попробовал программировать в университете Манчестера на одном из тех самых Атласов. Поплстоун хотел имплементировать логику, но обнаружил, что для удобной работы с деревьями мало аллокаций только на стеке. Чтоб разобраться, как программисты решают такие проблемы, он посетил ту самую летнюю школу по "нечисленным вычислениям", которая популяризировала псевдоCPL [Fox66] (Бурсталл также был знаком с этими лекциями, он писал рецензию на книгу [Burs67]). Наибольшее впечатление на него произвели доклад Стрейчи по CPL, LISP, расширения ALGOL 60 для работы со списками от радиолокационного института, доклад Ландина про то, как использовать стек и сборщик мусора для вычисления выражений. С этого времени Поплстоун стал последовательным пропонентом использования сборщика мусора.
|
||||
Проблема была в том, что если когда-то у него был доступ к компьютеру, но не было нужных знаний и идей, то сейчас знаний и идей было достаточно, но уже не было доступа к компьютеру, на котором он мог бы их воплощать в жизнь. Теперь он преподавал математику в университете Лидса и программировал на существенно более ограниченной университетской машине. Настолько, что выражения на Лиспе не помещались в "быструю" часть памяти, и Поплстоун придумал и имплементировал стековый язык COWSEL. Разумеется, это будет бесполезно на следующих машинах, но недостатки будут жить и десятилетия спустя.
|
||||
Кстати, о следующей машине: вот и она. Новая университетская машина, правда, работала только в пакетном режиме, а Поплстоун привык к интерактивной разработке и не обладал важной для программиста того времени способностью писать все правильно с первого раза. Или хотя-бы с сотого. Это означало, что то что Поплстоун делал на предыдущей машине за вечер, теперь могло требовать месяцы. Поплстоун так и не смог освоить старый подход к программированию и перенести на новую машину свой язык и пользоваться улучшенной производительностью.
|
||||
Ситуация складывалась не радужная. Поплстоун преподавал в Лидсе математику, к которой испытывал все меньше интереса и выпрашивал машинное время на более совместимой с ним машине за пределами университета для своих экспериментов. К счастью, на дворе весна 65-ого года и некий Дональд Мики заглянул в Лидс в поисках каких-нибудь "нечисленных вычислений". Вычисления были обнаружены и Поплстоун приглашен сделать доклад в Эдинбурге. Там он познакомился с Бурсталлом, который уговорил его экспериментально программировать в экспериментальной группе, что удалось очень легко [Popplestone].
|
||||
Robin John Popplestone was a mathematician who became fascinated with programming after first trying to program at the University of Manchester on one of those Atlas machines. Popplestone wanted to implement logic, but discovered that for convenient work with trees, stack-only allocation was not enough. To understand how programmers solve such problems, he attended that summer school on "non-numerical computation" that popularized pseudoCPL [Fox66] (Burstall was also familiar with these lectures; he wrote a review of the book [Burs67]). The greatest impression on him was made by Strachey's talk on CPL, LISP, ALGOL 60 extensions for list processing from the radar institute, and Landin's talk about how to use a stack and garbage collector to evaluate expressions. From that time, Popplestone became a consistent proponent of garbage collection.
|
||||
The problem was that if at one time he had access to a computer but not the necessary knowledge and ideas, now he had the knowledge and ideas but no access to a computer on which he could put them into practice. He now taught mathematics at the University of Leeds and programmed on a much more limited university machine. So limited that Lisp expressions did not fit in the "fast" part of memory, and Popplestone invented and implemented the stack language COWSEL. Of course, this would be useless on the next machines, but the shortcomings would live on for decades.
|
||||
By the way, about the next machine: here it is. The new university machine, however, worked only in batch mode, and Popplestone was used to interactive development and did not have the programmerly skill of getting everything right the first time. Or even the hundredth. This meant that what Popplestone did in one evening on the previous machine could now take months. Popplestone never managed to master the old approach to programming and port his language to the new machine to enjoy improved performance.
|
||||
The situation looked grim. Popplestone taught mathematics in Leeds, which he found increasingly uninteresting, and begged for machine time on a more compatible machine outside the university for his experiments. Luckily, it was the spring of 1965, and Donald Michie dropped by Leeds looking for some "non-numerical computations." The computations were found, and Popplestone was invited to give a talk in Edinburgh. There he met Burstall, who persuaded him to do experimental programming in the experimental group, which was easy to do [Popplestone].
|
||||
|
||||
### Энергия маленькой целевой машины.
|
||||
### The Energy of a Small Target Machine
|
||||
|
||||
> Для измученного имплементатора с маленькой целевой машиной мысль о том, что ему придется писать код для поиска свободных переменных в теле процедуры, и организовывать присвоение им значений перед выполнением этого тела, казалась слишком сложной.
|
||||
> Поплстоун, Р. Дж. Ранняя разработка POP [Popplestone].
|
||||
> For a weary implementer with a small target machine, the thought that he would have to write code to find free variables in a procedure body and organize assigning values to them before executing that body seemed too complex.
|
||||
> Popplestone, R. J. The Early Development of POP [Popplestone].
|
||||
|
||||
Экспериментальная группа Дональда Мики была задуман им как воспроизведение другого, существенно более масштабного эксперимента "Project MAC". В разные времена аббревиатура MAC расшифровывалась по разному, а в обсуждаемое время в первую очередь как Multiple Access Computer. Одна из первых (если не первая) система разделения времени была крупным успехом МТИ, привлекшим финансирование, которое было использовано для следующих, не таких успешных проектов. Мики посетил МТИ, и успехи проекта MAC, а также ростки будущих неуспехов проекта MAC произвели на него сильное впечатление. Он решил организовать что-то похожее в Великобритании, но поменьше и подешевле.
|
||||
Проект мини-МАК - и в узком и в расширенном смысле - должен был не просто воспроизвести большой МАК, а должен был сделать это другим путем. Это было хорошо для всего, что не любили в проекте МАК, например решатели теорем и логическое программирование [Emde06]. Хорошо и для того, к чему там были просто равнодушны, как к функциональному программированию. Проблема была в том, что некоторые вещи необходимые для ФП, такие как сборка мусора, в проекте МАК (пока что) любили. И, разумеется, в экспериментальной группе собирались все писать на ALGOL 60.
|
||||
Это угрожало полной катастрофой всем замыслам Поплстоуна. Он доказывал, что использование языка без сборщика мусора - ошибка, а добавить сборщик в имплементацию Алгола сложно потому, что не известно где на стеке указатели. Особых результатов это не принесло, но тут - в начале 66-го - экспериментальная группа наконец-то получила компьютер Elliott 4120. Поплстоун сразу же начал тайную имплементацию своего языка на нем, и вскоре имплементировал достаточно, чтоб языком заинтересовался Бурсталл.
|
||||
Бурсталл организовал для Мики демонстрацию, на которой тот попросил Поплстоуна написать небольшую функцию прямо у него на глазах, что тот легко сделал. Увидев интерактивное программирование, Мики стал энтузиастом языка. Не понравилось Мики только название COWSEL, так что как-то раз Поплстоун вернувшись из отпуска обнаружил, что язык уже называется POP (Package for Online Programming).
|
||||
Вскоре после того, как первая версия была готова и описана в апреле 66-го, а сборка мусора и интерактивное программирование завоевали себе место в мини-версии проекта MAC, Поплстоун и Бурсталл приступили к созданию POP-2.
|
||||
Примечательно то, что проработавший три года программистом в индустрии Бурсталл играл роль "теоретика", а программировавший в свободное от преподавания математики время Поплстоун - "практика". Видимо оба очень хотели передохнуть от того, чем занимались на работе.
|
||||
Разработку сначала планировали начать с нуля, чего не произошло. POP-2 унаследовал, по видимому, самую необычную фичу POP-1 - "открытый" стек. Как авторы POP, так и авторы CPL утверждают, что POP-2 произошел от CPL [Camp85] [Rich2000]. И это утверждение не так легко объяснить, даже с учетом крайне разреженного дизайн-пространства языков в те годы. Даже если выбирать из двух языков со сборкой мусора, одного имплементированного частично и с ошибками и второго, по большому счету, вообще воображаемого, то LISP выглядит как более правдоподобный предок, чем CPL. Изначально, возможно, планировалось сделать язык похожий на CPL, но ряд ключевых решений оттуда были отвергнуты Поплстоуном по "практическим" соображениям и заменены решениями, которые сам же Поплстоун впоследствии называл "ошибками" и "хаками".
|
||||
В сначала POP-2 планировали лексическую видимость как в ALGOL 60 (и CPL), но решили сделать динамическую. Это решение Поплстоун обосновывал проблемами имплементации: для того чтоб сделать и "открытый" стек и лексическую видимость на целевой машине было слишком мало регистров. Также Поплстоун считал, что язык с динамической видимостью проще отлаживать.
|
||||
Поплстоун еще и планировал имплементировать функции высшего порядка с помощью метапрограммирования, как в LISP, для чего достаточно дать программисту доступ к компилятору как функции. Что было не как в LISP, так это то, что Бурсталл знал, что этого недостаточно.
|
||||
Donald Michie's experimental group was conceived by him as a reproduction of another, much larger experiment, "Project MAC." At different times the acronym MAC was expanded differently, and in the period in question primarily as Multiple Access Computer. One of the first (if not the first) time-sharing systems was a major MIT success that attracted funding used for subsequent, less successful projects. Michie visited MIT, and the successes of Project MAC, as well as the seeds of its future failures, made a strong impression on him. He decided to organize something similar in the UK, but smaller and cheaper.
|
||||
The mini-MAC project - both in the narrow and the broad sense - was not supposed to merely reproduce the big MAC, but to do it in a different way. This was good for everything that was disliked in Project MAC, such as theorem provers and logic programming [Emde06]. It was also good for what they were simply indifferent to there, such as functional programming. The problem was that some things necessary for FP, such as garbage collection, were (so far) loved in Project MAC. And of course, in the experimental group they were going to write everything in ALGOL 60.
|
||||
This threatened a complete catastrophe for all of Popplestone's plans. He argued that using a language without garbage collection was a mistake, and that adding a collector to an ALGOL implementation was difficult because it was unknown where pointers were on the stack. This did not bring much result, but in early 1966 the experimental group finally received an Elliott 4120 computer. Popplestone immediately began a secret implementation of his language on it, and soon implemented enough that Burstall became interested in the language.
|
||||
Burstall organized a demonstration for Michie, in which he asked Popplestone to write a small function right in front of him, which he easily did. Seeing interactive programming, Michie became an enthusiast of the language. Michie disliked only the name COWSEL, so one day Popplestone returned from vacation and discovered that the language was already called POP (Package for Online Programming).
|
||||
Soon after the first version was ready and described in April 1966, and garbage collection and interactive programming had won their place in the mini version of Project MAC, Popplestone and Burstall began creating POP-2.
|
||||
It is notable that Burstall, who had worked for three years as an industry programmer, played the role of "theorist," while Popplestone, who programmed in the time free from teaching mathematics, was the "practitioner." Apparently both wanted a break from what they were doing at work.
|
||||
Development was initially planned from scratch, which did not happen. POP-2 inherited, apparently, the most unusual feature of POP-1: an "open" stack. Both the POP authors and the CPL authors claim that POP-2 descended from CPL [Camp85] [Rich2000]. This claim is not easy to explain, even given the extremely sparse design space of languages in those years. Even if one chooses between two garbage-collected languages, one implemented partially and with errors and the other largely imaginary, LISP looks like a more plausible ancestor than CPL. Initially, it may have been planned to make a language similar to CPL, but a number of key decisions from there were rejected by Popplestone on "practical" grounds and replaced by solutions that Popplestone himself later called "mistakes" and "hacks."
|
||||
At first POP-2 planned lexical scope as in ALGOL 60 (and CPL), but decided to make it dynamic. Popplestone justified this decision by implementation problems: to have both an "open" stack and lexical scope on the target machine there were too few registers. Popplestone also believed that a language with dynamic scope is easier to debug.
|
||||
Popplestone also planned to implement higher-order functions via metaprogramming, as in LISP, for which it is sufficient to give the programmer access to the compiler as a function. What was not like LISP was that Burstall knew this was not enough.
|
||||
|
||||
```
|
||||
function funprod f g;
|
||||
|
|
@ -825,7 +824,7 @@ function funprod f g;
|
|||
end;
|
||||
```
|
||||
[Burs68]
|
||||
И наш традиционный пример будет выглядеть так:
|
||||
And our traditional example will look like this:
|
||||
|
||||
```
|
||||
function map f l;
|
||||
|
|
@ -836,15 +835,15 @@ vars y; 1 -> y;
|
|||
map (lambda x y; x + y end(% y %)) [1 2 3]
|
||||
```
|
||||
|
||||
Поплстоун позднее вспоминал, что математика была их с Бурсталлом общим языком, который позволил им согласовать их цели в разработке POP-2 и достичь того, что язык, при всех его странностях можно было использовать в функциональном стиле. Но их сотрудничество ограничивало то, что Бурсталл интересовался применением математических идей более последовательно, а Поплстоун неохотно поддерживал его формальный подход [Popp2002].
|
||||
Можно ли его было использовать в функциональном стиле? К этому мы вернемся позже, когда будем обсуждать рождение функционального стиля. Но можно сказать определенно, что языки Эдинбургской программы оказались основаны не на нем, а на тех языках, использовать которые в функциональном стиле было удобнее.
|
||||
Компромиссные фичи, срезания углов и остатки POP-1 сильно подорвали модернизационный потенциал POP-2. Например, в Эдинбурге добавили статическую типизацию к ISWIM, но добавить ее к POP-2 оказалось слишком сложно: попытавшийся это сделать позднее Поплстоун обнаружил, что из-за открытого стека сигнатуры функций будут тайплевел-парсерами и посчитал, что не стоит связываться с такими сложностями [Popp2002].
|
||||
Важны ли были эти компромиссы для практичности? Сомнительно. Сейчас нам известно более-менее достоверно, что тот, кто может позволить такие дорогие фичи как сборка мусора или динамическая "типизация" - может позволить и лексическую видимость и компилятор, который сам ищет свободные переменные в лямбдах.
|
||||
Получился ли язык практичным? Он определенно применялся для написания программ больше, чем PAL и прочие ISWIMы того времени, но это не очень высокая планка. На нем была написана первая версия решателя теорем Бойера-Мура, одной из немногих программ, которая была переписана на LISP, а не с LISPа на какой-то другой язык. Первая имплементация POP-2 и более поздние для PDP-10 использовались для имплементации языков Бурсталла. Имплементация 80-х годов служила бэкендом для компилятора SML. Установленным в первой главе критериям практичности он соответствует. И для этого не понадобилось приносить все функциональные фичи в жертву как в BCPL. Это шаг вперед, по сравнению с обоекембриджской программой. Но не все в POP-2 было шагом назад по сравнению даже с планами для CPL. Но о прогрессивных фичах POP-2 и его влиянии на языки Эдинбургской программы мы подробнее расскажем ниже в соответствующих главах.
|
||||
Конечно проблемы с практичностью у POP-2 были, сборка мусора мешала программировать роботов, а из-за динамической "типизации" компилятор генерировал медленный код, который проверял теги и вызывал функции для каждой арифметической операции, что мешало писать на нем код для распознавание образов. Но такие проблемы не решены полностью и у современных "динамических" языков со сборкой мусора. [Popp2002]
|
||||
Почему на POP-2 вообще пытались писать код для управления роботами и распознавания изображений? Потому что он стал тем, чем хотели сделать CPL - единственным языком единственной машины, используемой в экспериментальной группе. И был он единственным не потому, что лучше всего подходил для всего "экспериментального программирования", которым в ней занимались. Операционная система Multipop68, ставшая ответом мини-MACа MACу большому, была системой основанной на языке, безопасность в которой обеспечивается инкапсуляцией и проверками языка. В данном случае проверками тегов в рантайме.
|
||||
Первоначальный план с аппаратной изоляцией процессов не удалось осуществить потому, что университет не смог приобрести подходящие жесткие диски для свопа. Со временем в Эдинбурге сделали более традиционную систему разделения времени с аппаратной защитой и свопом Multipop 70, но пользователи не любили её за медлительность и предпочитали продолжать пользоваться Multipop68 до получения новой машины PDP-10 в середине 70-х.
|
||||
Пока POP-2 был обязательным к нему привыкли, он был портирован на другие машины и внедрен в других университетах, стал популярным языком в британском ИИ, как Лисп в американском [Popplestone] [Popp2002]. Мики в 1969-ом даже основал компанию Conversational Software Ltd, которая пыталась POP-2 коммерциализировать [Howe07].
|
||||
Popplestone later recalled that mathematics was the common language between him and Burstall, which allowed them to align their goals in developing POP-2 and achieve that the language, with all its oddities, could be used in a functional style. But their collaboration was limited by the fact that Burstall was more consistently interested in applying mathematical ideas, while Popplestone was reluctant to support his formal approach [Popp2002].
|
||||
Could it be used in a functional style? We will return to this later, when we discuss the birth of the functional style. But we can say definitively that the languages of the Edinburgh program were based not on it, but on those languages in which it was more convenient to use a functional style.
|
||||
Compromise features, corner-cutting, and remnants of POP-1 seriously undermined POP-2's modernization potential. For example, in Edinburgh they added static typing to ISWIM, but adding it to POP-2 proved too difficult: when Popplestone later tried, he found that due to the open stack, function signatures would be type-level parsers and decided it was not worth dealing with such complexities [Popp2002].
|
||||
Were these compromises important for practicality? Doubtful. We now know more or less reliably that anyone who can afford such expensive features as garbage collection or dynamic "typing" can also afford lexical scope and a compiler that itself finds free variables in lambdas.
|
||||
Did the language turn out practical? It was definitely used to write programs more than PAL and other ISWIMs of the time, but that is not a very high bar. The first version of the Boyer-Moore theorem prover was written in it, one of the few programs that was rewritten into LISP rather than from LISP to some other language. The first POP-2 implementation and later ones for the PDP-10 were used to implement Burstall's languages. The 1980s implementation served as a backend for the SML compiler. It meets the practicality criteria established in the first chapter. And this did not require sacrificing all functional features as in BCPL. This is a step forward compared to the two-Cambridge program. But not everything in POP-2 was a step backward even compared to the plans for CPL. We will discuss the progressive features of POP-2 and its influence on the languages of the Edinburgh program below in the relevant chapters.
|
||||
Of course POP-2 had problems with practicality: garbage collection interfered with programming robots, and because of dynamic "typing" the compiler generated slow code that checked tags and called functions for each arithmetic operation, which made it hard to write image recognition code. But such problems are not fully solved even in modern "dynamic" languages with garbage collection [Popp2002].
|
||||
Why did they even try to write robot control and image recognition code in POP-2? Because it became what they had wanted to make CPL: the single language of the single machine used in the experimental group. And it was the single language not because it was best suited for all "experimental programming" done there. The Multipop68 operating system, the mini-MAC's answer to the big MAC, was a language-based system whose safety was ensured by encapsulation and language checks. In this case, tag checks at runtime.
|
||||
The original plan with hardware process isolation could not be carried out because the university could not purchase suitable hard disks for swapping. Over time, Edinburgh built a more traditional time-sharing system with hardware protection and swapping, Multipop 70, but users disliked its slowness and preferred to continue using Multipop68 until the arrival of a new PDP-10 machine in the mid-1970s.
|
||||
While POP-2 was mandatory, people got used to it, it was ported to other machines and deployed at other universities, and became a popular language in British AI, like Lisp in American AI [Popplestone] [Popp2002]. In 1969 Michie even founded Conversational Software Ltd, which tried to commercialize POP-2 [Howe07].
|
||||
|
||||
### Filtrage de motif
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue