?

Log in

No account? Create an account
Предыдущий пост Поделиться Пожаловаться Следующий пост
Юбилейно-техническое
sceptic
slobin

Мне тут напомнили, что у нас сейчас вялотекущий (в смысле только год, конкретной даты нет) юбилей Алгола-68. В СССР в 80-х он был довольно популярен, но писали на нём в основном в Ленинграде и Новосибирске, а в Москве не писали. Поэтому я с ним тогда не сталкивался, только прочитал парку книжек и ничего не понял. С тех пор я стал не то чтобы умнее (скорее наоборот), но немножко опытнее, и вот вчера сделал второй заход. Было интересно, умеет ли язык в функциональщину. Благо это вообще один из первых языков, где функции -- значения первого класса. И не просто указатели на код, как в сях, а полноценные функции с контекстом.

Увы, стандартный язык не умеет -- передавать функцию вовне её родного контекста явно запрещено (как и ссылку). Но в 1976, кажется, году Линдси предложил расширение языка -- частичную параметризацию, с которой уже можно. Немножко неуклюже -- захваченный контекст приходится помечать руками, но зато никаких неожиданных миграций из стека в кучу, как в няшной гошечке. Примерно так:

# Algol 68 Genie partial parametrization demo #

PROC make counter = PROC (INT) INT:
BEGIN
  HEAP INT counter := 0;
  PROC inc = (REF INT nn, INT n) INT: nn +:= n;
  inc(counter,)
END;

PROC (INT) INT pears := make counter;
PROC (INT) INT kiwis := make counter;

print((pears(100), new line));
print((kiwis(200), new line));
print((pears(400), new line));
print((kiwis(800), new line));

print(("done", new line))

Что тут происходит? При вызове make counter мы размещаем новый counter в куче, а потом частично параметризуем inc, и ссылка на этот counter оказывается замороженной в её первом параметре. Выглядит практически по современному. Ссылка на песочницу с этим примером: http://tpcg.io/S2GtO8

... Вычислительные средства находятся на клавиатуре справа ...

Метки:


  • 1
Не умеет да. Это было чуть не первым что мы в начале 1 курса проверили.

Хотя в реальности главным достоинством А-68 на ЕС-ке было то, что альтернативы-то были фортран и PL/I, который совсем уже мрачный и тормозной гроб был

PS: Забавно (хотя это из более поздних времен) Клиппер замыкания и функции высших порядков умеет (более того внутри него это даже используется)

(обиженно) PL/I, конечно, грязный уродец, но зато он работал! Из коробки работал. А наблюдать со стороны, как ваши ленинградские варяги пытаются привезённый с собой Алгол запустить -- это было грустное зрелище. В смысле, грустное, если он тебе нужен. А если тебе PL/I хватает, то весёлое. ;-)

... Сыграть с Европой на выход к морю ...


У нас-то он работал на отличненько. Под VM/370 про PL даже не вспоминали.

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

Там еще кстати схема раздельной компиляции и модульности крайне удачная - причем почему-то ее так никуда и не утащили (хотя как раз она позволяет естественным образом иерархически структурировать код)

HEAP INT counter := 0


Кстати не расширение - это сокрашение для INT counter = (HEAP INT := 0) - размещение значения в куче. На деле скорее должно быть что-то вроде:
PROC make counter = PROC (INT) INT:
BEGIN
  HEAP INT counter := 0;
  HEAP PROC inc = (REF INT nn, INT n) INT: nn +:= n;
  inc(counter,)
END;


В смысле что запись активации процедуры размещается не в стеке

Расширение не в этом месте, расширение в частичном вызове inc(counter,) , где мы из функции с двумя параметрами делаем функцию с одним. То, что ты предлагаешь, я пытался подумать, получается как-то не очень. Попытайся вообразить полный синтаксис -- у меня не вышло (в смысле, я перебрал несколько вариантов, все кривые). Любимое слово авторов языка -- "ортогональность", здесь ортогонально сделать трудно. А то, что у меня в посте -- оно реализовано и работает.

... Экономику - экономистам! ...


Частичный вызов на сам деле излишняя сущность - из серии синтаксического сахара (в OCaml кстати так и есть - там на самом деле функции от многих аргументов) -
PROC make = PROC (REF INT counter) PROC (INT) INT:
BEGIN
  HEAP INT counter := 0;
  PROC PROC (INT n) INT: counter +:= n;
END;


Оно в стандартном А68 даже оттранслируется - только работать не будет

// даже оттранслируется - только работать не будет

Вот о том и речь! А это работает. (предложенный вариант я первым делом попробовал, если что)

... Детектит овнера и лоадит его нативные фонты как дефолтовые ...

Чтобы работало достаточно записи активации функций совать в кучу, а не в стек (в той или иной степени так все сейчас и делают - в SML/NJ вообще стека нет - все в куче, что кроме прочего обеспечивает ему возможность сделать средствами языка параллелизм)

Частичное применение вообще вещь логически очень простая:
PROC apply = (PROC (REF INT, INT) fn, INT v) PROC (REF INT) VOID: PROC (REF INT r) VOID: fn (r, v)

  • 1