LINUX.ORG.RU

Ключи, записи с атрибутами и как всё это получше сделать

 , ,


0

2

Упёрся. Есть такая простая вещь, как синтаксис.

Вот примеры:

ключ используется сам по себе, без значения
ls -l *.c

в лиспе ключ почти всегда используется в паре со значением
(make-foo :a 1 :b 2) 

<img src="siski.png" alt="UML-диаграмма">

Но ведь есть и «синтаксис»

for i in a do 
Во всех примерах есть общность в том, что есть имена атрибутов и их значения, которые иногда есть, а иногда их нет. Их же можно назвать «ключевыми словами». Хотелось обобщить это так, чтобы было легко и приятно.

И сталкиваемся со следующими противоречиями: Если мы помечаем имя, то запись становится длиннее. Если мы не помечаем имя, то возможно возникновение неоднозначностей.

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

В языках типа С всё понятно - синтаксис там маленький и фиксированный. Все ключевые слова зарезервированы и не могут быть перепутаны с идентификаторами.

В языках с гомоиконностью, или просто в расширяемых языках так не получается. Сегодня я завёл переменную finally, а завтра в языке появилось ключевое слово finally и вот мы приехали.

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

(defsystem 
  :serial t
  :description "Some utilities by Budden, mostly public domain"
  :depends-on 
  (:alexandria :cl-fad :split-sequence :cl-utilities :named-readtables
   :cl-ppcre		
   :iterate-keywords :swank :decorate-function :closer-mop)
  )

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

(defsystem 
  serial t
  description "Some utilities by Budden, mostly public domain"
  depends-on 
  (alexandria cl-fad split-sequence cl-utilities named-readtables
   cl-ppcre		
   iterate-keywords swank decorate-function closer-mop)
  )
И стало меньше мусора в тексте. Вот. Тут надо принять стратегическое решение, которое потом вряд ли удастся исправить. Посоветуйте что-нибудь.

Пока что моя идея состоит в том, что необязательные ключи будут начинаться с тире, как в командной строке. Обязательные будут писаться просто как слова, но синтаксис будет понимать, ожидается ли сейчас ключевое слово или данные, и так мы сможем устроить, чтобы у нас одно слово могло служить и элементом синтаксиса, и идентификатором.

Что для литералов структур (т.е. для записей вида «имя=значение, имя=значение» я налагаю требование, чтобы на каждой строке располагался или один элемент (имя или длинное значение) или целое число пар:

объект хрень
 имя1 
  очень-длинное-значение-1
 имя2 значение2 
 имя3 значение3 имя4 // здесь нас подстрахует парсер
 имя5 значение 5 // несмотря на эту вторую ошибку
кно
★★★★★

Последнее исправление: den73 (всего исправлений: 1)

Проблема всех современных языков, в том числе и лиспа, в этом смысле, в том, что они стараются игнорировать контексты рантайм-вызовов в угоду простоты парсинга. То есть, вместо того, чтобы предоставлять свободу программисту, они заставляют его подчиняться правилам, да еще при этом и помогать разбирать код.

А мифы о лисповской особенности уже достали, нет там ничего особенного. Синтаксис там тоже есть. Спецформы являются синтаксисом в прямом смысле слова. Макросы также являются синтаксисом, только расширяемым и модифицируемым. Никакого кода как данных там и вовсе нет. Кроме того, лисп потерял свое основное свойство — дефолтное динамическое связывание.В старых лиспах это все было, но кануло в лету. Сейчас Io и tcl гораздо более лисп, чем сам лисп. Есть лишь пара маргинальных диалектов, которые остались лиспами в истинном значении слова.

xlsparse
()
Ответ на: комментарий от xlsparse

Ты мощно сказал, но я не всё распарсил.

стараются игнорировать контексты рантайм-вызовов в угоду простоты парсинга

Вот это о чём?

А мифы о лисповской особенности уже достали, нет там ничего особенного. Синтаксис там тоже есть.

Полностью с тобой согласен по второй части.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Вот это о чём?

это о том, что дизайнеру языка всегда выгодней всего, в первую очередь, из соображений производительности и оптимизации кода, связывать все свободные параметры со значениями на этапе компиляции, то же самое касается и синтаксических конструкций. Никто не хочет, чтобы какой-нибудь while в каком-нибудь рантайм-вызове означал что-то другое, отличное от дефолтного.

xlsparse
()

И сталкиваемся со следующими противоречиями: Если мы помечаем имя, то запись становится длиннее. Если мы не помечаем имя, то возможно возникновение неоднозначностей.

Я бы, наверное, из соображений простоты семантики выбрал явное указание параметров. Эта проблема, вообще говоря, очень хорошо видна на примере ООП-языков, разлисие между явной конфигурацией объекта, и функцией-конструктором. Мы создаем конструкторы, по сути, только для того, чтобы не указывать явно имена свойств, другого смысла в таких функциях нет. Но экономя на спичках, мы сталкиваемся с другим геммороем — надо запоминать порядок аргументов, и правила. То есть, освобождая руки мы захламляем голову. А в итоге, порой мы наблюдаем что в конструктор параметром подается объект, с помощью которого инициализируется новый объект, копированием полей. То есть, пришли к изначальному, к явному указанию полей, только через жопу конструктор.

xlsparse
()
Ответ на: комментарий от xlsparse

Кроме того, если у нас есть инициализация с явным указанием, мы всегда можем позже написать конструктор отдельно, т.е просто написать отдельную функцию-обертку.

оbject = new Object
object init(a = 1; b = 2)

objectConstructor = function(a, b){return new Object init (a = a, b = b)}
А вот обратное сделать проблематично

xlsparse
()
Ответ на: комментарий от xlsparse

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

Я бы сказал, что это выгоднее для возможности статического анализа кода.

den73 ★★★★★
() автор топика
Ответ на: комментарий от xlsparse

Но экономя на спичках, мы сталкиваемся с другим геммороем — надо запоминать порядок аргументов, и правила

Здесь-то у меня есть явные предпочтения. Если параметров мало, они обязательные и функция используется часто, то эти параметры должны быть неименованными. От запоминания должна спасать среда разработки с подсказками.

А в итоге, порой мы наблюдаем что в конструктор параметром подается объект, с помощью которого инициализируется новый объект, копированием полей

Это да, есть такое.

den73 ★★★★★
() автор топика
Ответ на: комментарий от The21century

Дальше ни читал.

Лучше бы ты дальше не писал. Зачем отметился? «Здесь был Вася»?

den73 ★★★★★
() автор топика
Ответ на: комментарий от xlsparse

Кроме того, если у нас есть инициализация с явным указанием

Это всё ясно и проблема не в этом. Проблема в том, что мне нравится предельная лисповая лаконичность:

(: object init a 1 b 2 :)
или
init(object,a,1,b,2); 
или
init(object,a 1,b 2); // хотя это уже далеко от лиспа

И вот тут встаёт вопрос: а не нужно ли пометить имена значком?

(: object init -a 1 -b 2 :)

den73 ★★★★★
() автор топика
Ответ на: комментарий от xlsparse

Но в Common Lisp - то так:

#S(foo :a 1 :b 2) (make-foo :a 1 :b 2)

И это более-менее защищает от ситуаций типа:

(make-foo :a a b :b)

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

какая разница a: a или :a a? скорей всего им так распарсить проще было, или просто отличиться захотели. Можно и -a a. разницы нет никакой. Тут смысл только в том, чтобы распарсить выражение. можно и вообще без меток сделать, имея в виду, что каждая пара — ключ значение.

xlsparse
()
Ответ на: комментарий от den73

Лучше бы ты дальше не писал

Я напишу. Топик и текст - бред, даже не утруждаешься членораздельно свои проблемы донести до других. Так что мое обратное пожелание - сам больше не пиши, и особенно в tag lisp. Спасибо.

The21century
()
Ответ на: комментарий от den73

Ух ты, туалетный юмор. Прими мои искренние соболезнования и проверься на паразитов. Удачи!

The21century
()
Ответ на: комментарий от den73

а не нужно ли пометить имена значком?

Если у тебя не лисп (нет требования «всё список»), то, мне кажется, лучше object.init(a=1 b=2).

monk ★★★★★
()

В лиспе так сделано скорее всего из-за нежелания вводить какой-то синтаксис для подобных вещей. И второй фактор то, что у языка основная задача—не компилироваться, а быть понятным человеку. Keyword отлично визуально отбивает элементы друг от друга. Использовать минусы вместо двоеточий? Гениально, на острие прогресса!

Так как ты изобретаешь велосипед, ты волен использовать более привычные по другим языкам способы:

foo(key1=value1, key2=>value2)
staseg ★★★★★
()
Ответ на: комментарий от The21century

Топик и текст - бред, даже не утруждаешься членораздельно свои проблемы донести до других.

ты видишь процесс преобразования den73 в анонiмуса

... больше не пиши, и особенно в tag lisp.

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

anonymous
()

Не любой синтаксис является синтаксическим мусором. Вообще, ИМХО какой синтаксис считать мусором, а какой нет - субъективно.

Gentooshnik ★★★★★
()
Ответ на: комментарий от The21century

Парень, серьёзно. Ты предлагаешь den73 больше не писать только потому, что лично ты неосилил уже им написанное.

Gentooshnik ★★★★★
()
Ответ на: комментарий от xlsparse

Ох. После первого коммента тов. xlsparse мне подумалось, что у него может быть хитрый план и лучше с ним не спорить, но после ЭТОГО коммента я уверен, что он просто ничего не понимает в лиспе и чуть ли не гордится этим. Первый коммент в новом свете предстал.

Gentooshnik ★★★★★
()
Ответ на: комментарий от staseg

Гениально, на острие прогресса! Так как ты изобретаешь велосипед, ты волен использовать более привычные по другим языкам способы:

Ну да, я же и привёл в пример ls -l. То есть обозначать ключи с помощью тире - это тоже традиционно. Насчёт того, что двоеточие позволяет отбивать элементы друг от друга - вот ты пока первый, кто понял суть проблемы. Но тут всё не так однозначно.

Во-первых, оно не всегда позволяет это делать. Смотри

(foo:bar :a bar:baz :m kk:ll)
Уже немного потерялись, правда? Во-вторых, естественно оформлять пару «имя-значение» вот так:
foo:bar
  a bar:baz
  m kk:ll
endb
И я хочу поставить соответствующие ограничения в синтаксисе.
foo:bar
  ключ1 
   зн1
  ключ2 зн2
  ключ3 зн3 ключ4 зн4
  ключ5 значение5 ключ6 // а вот так нельзя
   знач6               // так нельзя 
endb
В этом случае нафиг мне нужно двоеточие в начале строки, если начало строки и так отлично выделяет визуально? Хотя на самом деле, визуально почему-то с двоеточием в некоторых случаях выглядит красивее и я не могу себе это объяснить.

den73 ★★★★★
() автор топика
Ответ на: комментарий от monk

Если у тебя не лисп (нет требования «всё список»)

А это уже отдельная бездна. В C для некоторых вещей (if) сделан синтаксис, а для других функциональная нотация f(x,y). С точки зрения лиспа, выбор сделан совершенно произвольно. А как делать в новом языке? Нет никакого смысла держаться традиции С, потому что там не всё плохо сделано, да и вообще там мало всего.

А как тогда выбирать? Оказывается, лисп хорош ещё и тем, что решает эту неоднозначность всегда в одну сторону.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Гениально, на острие прогресса!

обозначать ключи с помощью тире - это тоже традиционно

Похоже, staseg слишком тонко поиронизировал.

Там довольно интересная история с этими минусами. Ну и вообще с сокращениями, которые достались от раннего UNIX. Минус выбрали потому что для более логичного плюса нужно было зажимать еще и шифт, а это было непросто. О многосимвольных конструкциях вообще не думали. Такое вот юзабилити прошлого века, которое осталось с нами

http://www.faqs.org/docs/artu/ch10s05.html

The original Unix style evolved on slow ASR-33 teletypes that made terseness a virtue; thus the single-letter options. Holding down the shift key required actual effort; thus the preference for lower case, and the use of “-” (rather than the perhaps more logical “+”) to enable options.

Deleted
()
Ответ на: комментарий от den73

С точки зрения лиспа, выбор сделан совершенно произвольно

Нет. Синтаксис в лиспе всё, что в нём называется макросы и специальные формы.

Оказывается, лисп хорош ещё и тем, что решает эту неоднозначность всегда в одну сторону.

Но не всегда удобно читается. Никогда не задумывался. почему (let ((a 1) (b 2)) ...), а не (let (a 1 b 2) ...) ? Без второго уровня скобок было бы нечитаемо после полудюжины переменных. А «=» (или «=>») между элементами явно привязывает их друг к другу.

Ну и в качестве идеального синтаксиса лучше рассматривать не Си, а Javascript или Perl.

monk ★★★★★
()
Ответ на: комментарий от Deleted

The GNU double-hyphen option leader was chosen so that traditional single-letter options and GNU-style keyword options could be unambiguously mixed on the same command line.

Вот. Ещё один смысл добавления значка - это чтобы сложнее было перепутать ключ и собственно аргумент. В случае, когда у ключа может быть не один, а ноль или два аргумента, значок становится обязательным - он отделяет соседние опции друг от друга.

Касаемо минуса и плюса - ничего не изменилось с тех пор. Шифт так и остался.

den73 ★★★★★
() автор топика
Ответ на: комментарий от monk

Синтаксис в лиспе всё, что в нём называется макросы и специальные формы.

Я имел в виду, что в С косинус пишется как функция, а для if ... else сделан оператор с ключевыми словами. А в лиспе и if, и косинус - одинаково пишутся, со скобочками и без ключевых слов.

Так вот вопрос в чём: а почему именно if должен быть словами, а косинус - функцией?

Можно ведь и косинус сделать оператором, и if записать со скобочками. Как-то так можно было в C сделать:

if(условие,выражение,альтернатива)
И этот выбор будет стоять перед каждым разработчиком DSL, если мы сделаем расширяемый язык в котором есть _и_ операторы, _и_ запись в виде функций. Что хуже всего, каждый пользователь должен будет помнить сделанный нами выбор, и я не могу понять, какое мнемоническое правило можно положить в основу, чтобы делать этот выбор всегда автоматически.

Вот какая бездна сейчас вглядывается в меня.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 2)
Ответ на: комментарий от monk

Ну и в качестве идеального синтаксиса лучше рассматривать не Си, а Javascript или Perl.

Мне больше нравится бейсик. В нём нет лишних точек с запятой (от которых ещё и грустные смайлики). Конец строки - очень хороший естественный разделить. В JS, если я правильно помню, точки с запятой опциональны - это вообще маразм.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Так вот вопрос в чём: а почему именно if должен быть словами, а косинус - функцией?

В терминах лиспа: почему (loop ...) должен быть словами, а (do ...) функцией?

если мы сделаем расширяемый язык в котором есть _и_ операторы, _и_ запись в виде функций.

Оператор — всегда синтаксис (АКА макрос). Функция — как повезёт.

Есть и такие макросистемы: http://nim-lang.org/docs/macros.html

какое мнемоническое правило можно положить в основу, чтобы делать этот выбор всегда автоматически.

Если аргументы не вычисляются, то желательно оператор.

monk ★★★★★
()
Ответ на: комментарий от den73

точки с запятой опциональны - это вообще маразм.

Почему опциональные переносы не маразм, а опциональные точки с запятой маразм? В конце концов «t=a; a=b; b=t» на одной строчке понятней сморится.

monk ★★★★★
()
Ответ на: комментарий от monk

Если аргументы не вычисляются, то желательно оператор.

Ну это иллюзорное правило, вот контрпример (если я не совсем забыл С) .

#define OR(a,b) ((a)||(b))

В терминах лиспа: почему (loop ...) должен быть словами, а (do ...) функцией?

loop - это аномалия, не укладывающаяся ни в какие рамки.

Оператор — всегда синтаксис (АКА макрос). Функция — как повезёт.

А вот в TCL всё - операторы. И в этом тоже есть свой шарм.

Во многих языках print - оператор (скажем, во 2 питоне). Хотя он вычисляет свои аргументы. Да и вообще есть языки XBase (CLipper, FOXPRO), в которых операторов гооораздо больше, чем в С, в т.ч. вычисляющих свои аргументы. В позднем клиппере были даже замыкания (или что-то наподобие) и макросы. И ничего так себе языки, приятны на вид.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

(foo:bar :a bar:baz :m kk:ll)

Поэтому нужно стащить удачное, а теперь уже и привычное многим, решение из других языков

(foo:bar a=bar:baz m=kk:ll)

Я в своих игрушечных лиспах ленился делать парсер, а от двоеточечного ада избавлялся так:

(foo/bar :a bar/baz :m kk/ll/zz)

Т.е. использовал '/' для прохода в неймспейс.

Хотя на самом деле, визуально почему-то с двоеточием в некоторых случаях выглядит красивее и я не могу себе это объяснить.

Многострочная конструкция с пробелами выглядит слишком громоздко, а однострочник с двоеточиями—элегантно и лаконично, вот и все объяснение.

staseg ★★★★★
()
Ответ на: комментарий от den73

вот контрпример
Во многих языках print - оператор

Это как раз аномалии. Просто, с точки зрения чтения, удобно, когда видно, можно ли воткнуть произвольное выражение или кусок кода будет разобран вручную (привет cl:iterate).

Хотя, не настаиваю. Синтаксис по определению — вопрос вкуса.

monk ★★★★★
()
Ответ на: комментарий от staseg

Многострочная конструкция с пробелами выглядит слишком громоздко, а однострочник с двоеточиями—элегантно и лаконично, вот и все объяснение.

Не. В многострочнике красивее с двоеточиями. Они как бы образуют собой линию отступа. Может быть, это у меня такой глюк.

Однострочник плох тем, что строчка быстро заканчивается.

den73 ★★★★★
() автор топика
Ответ на: комментарий от monk

Просто, с точки зрения чтения, удобно, когда видно, можно ли воткнуть произвольное выражение или кусок кода будет разобран вручную (привет cl:iterate).

Мне кажется, это всё же отчасти иллюзия.

for i = 1 to 10 
Можно только запомнить, что i - это «особая статья», а 1 и 10 - обычные выражения. А операторы print очень хороши - они позволяют избавиться от кучи лишних скобок.

Короче понятно, что нужно как-то пройти мимо вопроса про синтаксис, иначе мы не доживём до версии 1.0 никогда.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

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

a.b(x).c(y).d
и
d (c (b a x) y)
Сишная запись выражает причинно-следственную связь. Причина слева, читаем слева направо и приходим к следствию. А лисповую запись нужно читать из середины наружу. Или читать от следствия к причине. В обоих случаях - ужасно! Здесь я ещё выкинул наружную пару скобок, типа мы её как-то угадали по концу строки.

den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 2)
Ответ на: комментарий от den73

то в лиспообразных языках плохо выглядят цепочки обращений. Вот сравниваем:

(send* a (b x) (c x) d)

выглядит не сильно хуже

a.b(x).c(y).d

monk ★★★★★
()
Ответ на: комментарий от den73

Можно только запомнить, что i - это «особая статья», а 1 и 10 - обычные выражения.

Вот! А запоминать такие особенности, если написано for(i, 1, 10, print(i)) гораздо сложнее.

monk ★★★★★
()
Ответ на: комментарий от monk

По-моему, это ортогонально. Другое дело, что когда часть со скобками, часть без скобок, то за счёт чередования того и сего общее соотношение сигнал/шум в тексте повышается. Поэтому языки с разными разделителями лучше. Clojure лучше CL. Потому что разные скобки задействованы. Но это хорошо, когда правила использования разных скобок однозначны. А если нет?

send* - это хорошо, но есть ООП и есть ООП. Есть настоящее ООП и есть С(++), где не ООП, а записи (которые быстро работают). Т.е. если send* имеет семантику цепочки как в C, то есть предмет для разговора. А откуда эта конструкция?

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

И если уж все проблемы в одну кучу валить, то в лиспообразных языках плохо выглядят цепочки обращений. Вот сравниваем:
a.b(x).c(y).d

Можно написать макрос

(-> a
    (b x)
    (c y)
    d)

который вернёт ту самую причинно-следственную связь

anonymous
()
Ответ на: комментарий от den73

А откуда эта конструкция?

Из Racket. Только я ошибся, в данном случае не send*, а send+. send* все методы у первого аргумента (объекта) вызывает.

Поэтому языки с разными разделителями лучше.

Типа

_1.mapped._2.mapped %~ succ $ ([(42, "hello")],"world")
?

monk ★★★★★
()
Ответ на: комментарий от monk

В общем, я вот что думаю. Можно сделать, чтобы были и функции, и операторы, и оставить автору библиотеки право выбора. Например, в print, как правило, не важно возвращаемое значение (допустим, неудачу печати как-то оформим исключением). Цикл традиционно является оператором.

Если нужно подставить оператор в функцию, окружаем его в смайлики:

пусть x = (: если б >> г то б иначе г кне :)

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Соответственно, в стиле clojure, оператор является литералом структуры. Список аргументов ф-ии является литералом списка.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Ещё немного поупражнялся с синтаксисом. Вот что получается. Исходная ф-я на лиспе:

(defun Xi (PipeKind FlowMode Rey)
  "множитель Дарси для трубы (без потоков)" 
  (cond
   ((= Rey 0.0) 0.0)
   (t
    (ecase PipeKind
      (Pipe
       (ecase FlowMode
         (Lam (/ 64.0 Rey))
         (Turb1 (/ 0.3164 (expt Rey 0.25)))
         (Turb2 (+ 0.0032 (/ 0.221 (expt Rey 0.237))))
         ))
      (Channel
       (ecase FlowMode
         (Lam (/ 96.0 Rey))
         )
       )))))
Она же переведённая на Яр только в части структуры текста.
defun Xi (PipeKind, FlowMode, Rey)
 docstring "множитель Дарси для трубы (без потоков)" 
 body
  return
   cond 
    (
     (:Rey == 0:) 0.0,
     t 
      ecase PipeKind 
       (
        Pipe 
         switch FlowMode 
          default error
          test 'eq 
           (
            Lam   64.0 / Rey,
            Turb1 0.3164 / expt(Rey,0.25)),
            Turb2 0.0032 + (:0.221 / expt(Rey,0.237):)
           ) 
         ends, 
        Channel 
         ecase FlowMode 
          (
           Lam 96.0 / Rey
          ) 
         ende
       ) 
      ende 
    )
   endc
endd
Всё здесь гомоиконно и чётко с идейной точки зрения. Везде, где переменное число элементов, используются списки вида (элемент1,...,элементN). defun, cond и ecase - это литералы записей. Преодоление приоритетов в любом месте сделано с помощью смайликов.

Но что-то это некрасиво :(

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

А зачем вообще нужны операторы наподобие print или for? Когда всё это можно реализовать как функции/макросы. Или я чего-то не понимаю?

anonymous
()
Ответ на: комментарий от anonymous

В лиспе основной недостаток - это избыток скобок. Мало кто это понимает. Представь себе лес - одни деревья. Как ориентироваться? А если то дерево, то куст, то поляна, то просека, то ориентироваться уже легче. Т.е., нужно чтобы исходный текст в должной мере пестрел. Т.е. сделать так как ты говоришь - можно, но не нужно.

den73 ★★★★★
() автор топика
Ответ на: комментарий от den73

Что-то XML получается. У каждой конструкции есть имя, с к-рого она начинается, атрибуты и содержимое. Прямо XML. Попробуем обособлять атрибуты с помощью (% %), ведь они нужны не всегда. А за ними идёт тело. Условие на списки смягчим и позволим вставлять в грамматику список пар имя-значение, идущий через пробел. Типа &body.

defun Xi (PipeKind, FlowMode, Rey)
 (% docstring "множитель Дарси для трубы (без потоков)" %)
 return
  cond 
   // ожидается последовательность 
   // ВЫРАЖЕНИЕ ОПЕРАТОР ... ВЫРАЖЕНИЕ-N ОПЕРАТОР-N
   (:Rey == 0:) 0.0 
   t 
    ecase PipeKind 
     Pipe 
      switch FlowMode 
       (% default error test 'eq %) 
       Lam   64.0 / Rey
       Turb1 0.3164 / expt(Rey,0.25)
       Turb2 (: // не поместился в строку - ставь скобки
        0.0032 + 0.221 / expt(Rey,0.237)
       :)
      ends
     Channel 
      ecase FlowMode 
       Lam 96.0 / Rey
      ende
    ende 
  endc
endd
den73 ★★★★★
() автор топика
Последнее исправление: den73 (всего исправлений: 5)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.