Lisp без скобок
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 04.12.06 19:20
Оценка: 319 (34) +1

Parentheses? What parentheses? I haven't noticed any parentheses since my first month of Lisp programming. I like to ask people who complain about parentheses in Lisp if they are bothered by all the spaces between words in a newspaper...
-- Kenny Tilton <tilt@liii.com>

Похоже что время от времени интерес к Лиспу просыпается не только у меня. Я думаю (надеюсь) что сия подборка материала буде интересна многим. (Заранее прошу извинения у Схеме-ров, в некоторых случаях я под словом Лисп буду понимать и Лисп, и Схему).

Не секрет, что подавляющее число людей, впервые (или не впервые) увидев Лисп, испытывают самые разные эмоции от крайнего скептицизма ("Никто не использует Лисп! Бессмысленная куча скобок! Мёртвый язык! Не для настоящей работы! Какой смысл изучать?"), ступора ("Ах**ть, ничего не понятно!") и крайнего удивления: "Неужели есть перцы, которые в этом чего-то разбирают?" Некоторые люди по-человечески жалеют лисперов: "Эхх, должно быть тяжело разбираться со всеми этими скобками..."

К счастью находятся особо любознательные, которые и сами решают разобраться, чего же такого особенного в Лиспе, что можно терпеть эту кучу скобок. Они копают чуть-чуть глубже и однажды выясняют, что есть reader macros, и с помощью них можно воротить что душе заблагорассудится вплоть до полной замены синтаксиса. И ведь воротят же!

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

Начну с того, что сам Пол Грэхэм в описании языка Arc соглашается, что синтаксис Лиспа бывает некомфортен для чтения и записи и высказывает идею, что некоторые скобки можно вывести из отступов и переводов строки. В частности, если строка содержит больше одного S-выражения, следовательно должен существовать префикс в списке для этих S-выражений. Если строки имеют одинаковый отступ, то они должны быть продолжением какого-то S-выражения. Выражения, где разделителями являются переводы строк и отступы получили название I-выражений.
... // префикс должен быть где-то здесь
  (+ 1 2) (- 3 4) // значит здесь должна быть закрывающая скобка
// проверим дискриминант 
(> (/ (+ (- b) (sqrt (- (* b b) (* 4 a c)))) (* 2 a)) 0)
// запись того же в I-выражениях
>
  /
    +
      - b
      sqrt
         -
           * b b
           * 4 a c
    * 2 a
  0


Итак, проект Lispin, то есть LISP INdented. Попытка заменить некоторые уровни вложенности отступами, тем самым уменьшив количество скобок, то есть замены S-выражений на I-выражения. На страничке проекта есть окошко, куда можно чего-нибудь ввести и посмотреть, как расставятся скобки.
defun factorial (n)  if (<= n 1)
    ^ 1
    * n
      factorial (- n 1)

К сожалени есть только для Схемы. создатель Bill Birch хотел сделать для Лиспа, но преждевременно запостил свой результат в comp.lang.lisp (об этом ниже)

Scheme Request for Implementation #49. Всего в 5 экранах вполне законченная референсная имплементация той же идеи замены некоторых S-выражений на I-выражения. Здесь все выражения эквивалентны:

  let
   group
    foo
     + 1 2
    bar
     + 3 4
   + foo bar
  let
   group
    foo (+ 1 2)
    bar (+ 3 4)
   + foo bar
  (let
   (group (foo (+ 1 2)) (bar (+ 3 4)))
   (+ foo bar))
Далее можно упомянуть TwinLisp — это транслятор-фронтэнд из TwinLisp кода в стандартный Common Lisp код. В противоположность Лиспу TwinLisp использует унарные и бинарные операторы типа +, *, блоки в стиле Java и тому подобный сахар. Программы в TwinLisp выглядят примерно так (результат трансляции ниже):
progn {
    a = 0
    progn {
        b = 1
        a = b+2
        a }}

(PROGN (LET (A) (SETF A 0) (PROGN (LET (B) (SETF B 1) (SETF A (_+_ B 2)) A))))

В общем-то попытка так радикально отойти от синтаксиса Лиспа при этом сохранив возможность обращения к символам стандартного Лиспа привела к не всегда хорошо читаемым результатам (символы Лиспа должны предваряться амперсандом плюс ещё много правил всяких):
mac &infinite-loop (**body) {`do () { $@body }}

(DEFMACRO INFINITE-LOOP (&BODY BODY) `(DO NIL (NIL) ,@BODY))


Дальнейшее развитие идеи исправления синтаксиса Лиспа может зайти достаточно далеко, и скорее всего это будет уже самостоятельный язык. Самый известный пример: Dylan (уже даже не напоминает Лисп ):
define macro let-com-interface
  { let-com-interface ?:name :: ?type:expression = ?value:expression;
    ?:body }
  => { let ?name :: ?type = ?value;
       block()         
         ?body
       cleanup
         release(?name)
       end }
end macro let-com-interface;

define function as-com-type(type, interface-ptr)
  let (result, com-interface) = QueryInterface(interface-ptr, 
    dispatch-client-uuid(type));  
  if(SUCCEEDED?(result))
    pointer-cast(type, com-interface);
  else
    #f
  end if;
end function as-com-type;


Есть ряд любительских экспериментальных имплементаций I-выражений, например здесь, здесь, здесь и здесь.

Не могу не упомянуть страницу David A. Wheller'а Readability. На это странице есть ссылки на реализацию предлагаемого им "сахара", кроме того там можно найти ссылку на очень большую и детальную статью "Readable s-expressions and sweet-expressions: Getting the infix fix and fewer parentheses in Lisp-like languages. Если очень коротко, то Дэвид предлагает формировать "sweet-expressions" тремя способами:
1. Отступами (то есть те самые I-выражения).
2. Выносом имён за скобки. То есть термы в форме "NAME(x y ...)" без пробела между "N
AME" и "(" интерпретируются как "(NAME x y ...)". Если содержимое в скобках инфиксное выражение, то оно рассматривается как один параметр.
3. Инфиксная запись. Выражения автоматически интерпретируются как инфиксные выражения, если их второй параметр является инфиксным оператором ("инфиксный оператор" задаётся регэкспом "[+-\*/<>=&\|\p{Sm}]{1-4}|\:"), первый параметр не инфиксный оператор и выражение состоит из как минимум трёх параметров. Иначе выражение интерпретируется как нормальное S-выражение. Инфиксные выражения должны иметь нечётное количество параметров где чётные места занимают бинарные инфиксные операторы. Операторы должны отделяться пробелами. Приоритет поддерживается. Таким образом
2 + y * -(x)   эквивалентно   (+ 2 (* y (- x)))


Многие реализации Схемы (например MzScheme) поддерживают стиль, (либо поддержка содержится в библиотеке), когда можно комбинировать различные скобки, что немного улучшает читаемость кода, но при этом оставляет S-выражения самими собой:
(define preved [lambda (x) {+ x 1}])



Другой путь борьбы со скобками — это сохранить скобки, но не показывать пользователю, дабы не травмировать его чувствительную натуру Наверное самый шикарный результат — это плагин color-box для Emacs:


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

Это скриншот японского редактора GTEdit.

Собственно от идеи редактирования S-выражений один шаг до идеи редактирования сразу деревьев, но редактора такого я пока не видел.

Подозреваю, что о Lispworks, Allegro CL и SBCL все знают. Обеспечиваемый сервис настолько высок, что скобы совершенно не напрягают. А вот про CUSP — плагин для Эклипса лично я узнал совсем недавно.



Наконец последний, третий подход в борьбе со скобками — это борьба со стереотипами новичков и профанацией. Характерный пример — A Beginners' Meta FAQ for comp.lang.lisp:

1. Spend some time learning a little Lisp before trying to ask questions on c.l.l....

2. Lisp beginners are often scared by Lisp's novel syntax, and sometimes think to propose a way to "simplify" it by making it look like something they are familiar with (usually their favorite programming language)...
Generally speaking, if you are a Lisp beginner it's best not to try to make suggestions of how Lisp should be fixed until you understand it relatively well...


Несмотря на кажущуюся привлекательность (частичной) замены S-выражений на I-выражения, этот подход встретил почти полное непонимание среди как опытных лисперов, так и не очень опытных. Например, упомянутый выше Lispin вместе с создателем порвали на лоскуты (имеется ввиду что реакция была от скептической до резко негативной):
ANNOUNCE: Lisp Without Parentheses Project (Lispin) Site Open
Lisp and Scheme with fewer parentheses
(поэтому он обиделся и не хочет больше заниматься проектом Lispin).

Также упомянутая выше работа David A. Wheller также стала причиной жарких разборок
sweet-expressions instead of s-expressions?
(Неприятная черта в Лисп-коммьюнити (может только на c.l.l.) — просто зашкаливающая "доброжелательность" к новичкам. Можно конечно понять, но всё равно не очень ...)

Самый оригинальный аргумент, который почти всегда непонятен из-за казалось бы очевидной противоречивости, это "There's no parenthesis in lisp". Тем не менее внятное и подробное объяснение этого тезиса
здесь. Суть сводится к следующему: профессионалы глядя на S-выражение видят сразу дерево, поэтому они не видят скобок!
defun
 |--fact
 |--<parameterList>
 |  `--N
 `--if
    |-->
    |  |--N
    |  `--1    
    |--*
    |  |--N
    |  `--fact
    |     `--+
    |        |---1
    |        `--N    
    `--1


На самом деле слова в защиту скобок можно найти у многих авторов: Пола Грэхема, Питера Норвига, Питера Зибеля и прочих "лисп-хакеров", и все утверждают, что скобки не зло, а большое благо. Можно этим парням верить на слово? Стопудово можно. Но до наступления просветления нужно как то жить, и на мой взгляд лучше выбрать редактор поудобнее.

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

PS: увы, много буков, но надеюсь не смертельно.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re: Lisp без скобок
От: cl-user  
Дата: 05.12.06 09:56
Оценка: 2 (2)
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Похоже что время от времени интерес к Лиспу просыпается не только у меня. Я думаю (надеюсь) что сия подборка материала буде интересна многим.


Ну, только если новичкам — может они поймут, что слегка познакомившись с лиспом, не надо лезть на форумы с вопросом "А как можно избавиться от скобок?", и уж тем более не надо вопить "Я знаю как избавиться от скобок!.."

LCR>Не секрет, что подавляющее число людей, впервые (или не впервые) увидев Лисп, испытывают самые разные эмоции от крайнего скептицизма ("Никто не использует Лисп! Бессмысленная куча скобок! Мёртвый язык! Не для настоящей работы! Какой смысл изучать?"), ступора ("Ах**ть, ничего не понятно!") и крайнего удивления: "Неужели есть перцы, которые в этом чего-то разбирают?" Некоторые люди по-человечески жалеют лисперов: "Эхх, должно быть тяжело разбираться со всеми этими скобками..."


Ага, меня в лиспе больше всего раздражает шрифт, который стоит по-умолчанию в просмотрщике винрара — из-за него действительно блевануть хочется при виде лиспового кода

LCR>К счастью находятся особо любознательные, которые и сами решают разобраться, чего же такого особенного в Лиспе, что можно терпеть эту кучу скобок. Они копают чуть-чуть глубже и однажды выясняют, что есть reader macros, и с помощью них можно воротить что душе заблагорассудится вплоть до полной замены синтаксиса. И ведь воротят же!


К счастью ли? А может просто чуть-чуть посмотреть по сторонам, почитать доку и понять, что ридер (reader) полностью в твоих руках и ты можешь творить с ним что-угодно (причём прямо в теле модуля/файла/блока/функции, где это особенное поведение ридера необходимо — привет немерлистам! )

Единственная "священная корова" — код есть список, т.е. просто список. И как бы ты не переопределял readtable, задание и обработка списка должны оставаться такими-же простыми, как и с помощью скобок. Иначе макры (кодогенерация) летят ко всем чертям, а следом и ты со своим "изобретением"

LCR>Здесь я изложу свой обзор о том, как люди боролись со скобками вместо того чтобы полюбить их, ну или хотя бы отнестись к ним с пониманием.


Обзор того, _что_ и _как_ не следует делать

LCR>Дальнейшее развитие идеи исправления синтаксиса Лиспа может зайти достаточно далеко, и скорее всего это будет уже самостоятельный язык. Самый известный пример: Dylan (уже даже не напоминает Лисп ):


Ничего язычёк. Но реализация "хромает" вместе со своей лицензией (ИМХО). И остаётся вопрос (тот-же ,что и к немерлистам) — получив body (блок кода) — я могу его расчленить, проанализировать отдельные части, и собрать из разных частей другой (новый — как угодно) блок кода?

Ни дока по дилану, ни по немерле на дали положительного ответа на данный вопрос (я подчёркиваю — я не говорю, что это не возможно — я просто не знаю — возможно ли это )

LCR>Наконец последний, третий подход в борьбе со скобками — это борьба со стереотипами новичков и профанацией.


Я бы сказал — единственный

LCR>(Неприятная черта в Лисп-коммьюнити (может только на c.l.l.) — просто зашкаливающая "доброжелательность" к новичкам. Можно конечно понять, но всё равно не очень ...)


А вот этого не надо. Нормально там относятся (если не прадлагать убрать скобки из лиспа ). В крайнем случае промолчат. Но если новичёк в лиспе — "гуру" в другом языке и сразу начинает учить всё лисп-сообщество как им жить дальше — какую реакцию вы ожидаете?

LCR>Самый оригинальный аргумент, который почти всегда непонятен из-за казалось бы очевидной противоречивости, это "There's no parenthesis in lisp". Тем не менее внятное и подробное объяснение этого тезиса

LCR>здесь. Суть сводится к следующему: профессионалы глядя на S-выражение видят сразу дерево, поэтому они не видят скобок!

Я бы заменил "не видят" на "не замечают (пока парность не нарушается, но об этом заботится редактор, компилятор ругается)"

LCR>На самом деле слова в защиту скобок можно найти у многих авторов: Пола Грэхема, Питера Норвига, Питера Зибеля и прочих "лисп-хакеров", и все утверждают, что скобки не зло, а большое благо. Можно этим парням верить на слово? Стопудово можно. Но до наступления просветления нужно как то жить, и на мой взгляд лучше выбрать редактор поудобнее.


Этот абзац нужно было выделить жирным курсивом

LCR>Ну вот, в принципе всё что я хотел сказать. Спасибо за внимание.


Продолжение будет?
Re[2]: Lisp без скобок
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 05.12.06 15:49
Оценка:
cl-user,

CU>Ага, меня в лиспе больше всего раздражает шрифт, который стоит по-умолчанию в просмотрщике винрара — из-за него действительно блевануть хочется при виде лиспового кода


(offtop (? FAR))


LCR>>К счастью находятся особо любознательные ...


CU>К счастью ли?


Вопрос не совсем технического плана...


CU> А может просто чуть-чуть посмотреть по сторонам, почитать доку и понять, что ридер (reader) полностью в твоих руках и ты можешь творить с ним что-угодно (причём прямо в теле модуля/файла/блока/функции, где это особенное поведение ридера необходимо — привет немерлистам!)


CU>Единственная "священная корова" — код есть список, т.е. просто список. И как бы ты не переопределял readtable, задание и обработка списка должны оставаться такими-же простыми, как и с помощью скобок. Иначе макры (кодогенерация) летят ко всем чертям, а следом и ты со своим "изобретением".


CU>И остаётся вопрос (тот-же ,что и к немерлистам) — получив body (блок кода) — я могу его расчленить, проанализировать отдельные части, и собрать из разных частей другой (новый — как угодно) блок кода?


CU>Ни дока по дилану, ни по немерле на дали положительного ответа на данный вопрос (я подчёркиваю — я не говорю, что это не возможно — я просто не знаю — возможно ли это )


Ну цитировать можно не зная точного AST.
define macro with-mutex
  { with-mutex (?mutex:expression) ?code:body end }
    => { let mutex = ?mutex;
     check-error(pthread-mutex-lock(mutex));
     block ()
       ?code
     cleanup
       check-error(pthread-mutex-unlock(mutex));
     end block; }
end with-mutex;

;;; здесь будет подставлен макрос с параметрами mutex и телом ниже
with-mutex (mutex)
  format(*standard-output*, "The mutex is locked.\n");
end;

Аналогичным образом можно и в Немерле. Но вот именно так, как ты говоришь (расчленить, потом собрать) я думаю лучше спросить у немерлистов. Да, и хорошо бы знать, что за расчленение-сборка нужна?


CU>Обзор того, _что_ и _как_ не следует делать


Не совсем так. Я старался сохранить позицию стороннего наблюдателя (правда не очень получилось). Например, Пол Грэхэм в Arc вводит некоторые изменения синтаксиса. И для себя ты можешь творить что угодно. И редакторы... Есть новая идея? Покажи! Так что не всё так однозначно.


LCR>>Наконец последний, третий подход в борьбе со скобками — это борьба со стереотипами новичков и профанацией.


CU>Я бы сказал — единственный


Повторюсь, не всё так однозначно.


LCR>>(Неприятная черта в Лисп-коммьюнити (может только на c.l.l.) — просто зашкаливающая "доброжелательность" к новичкам. Можно конечно понять, но всё равно не очень ...)


CU>А вот этого не надо. Нормально там относятся (если не прадлагать убрать скобки из лиспа). В крайнем случае промолчат. Но если новичёк в лиспе — "гуру" в другом языке и сразу начинает учить всё лисп-сообщество как им жить дальше — какую реакцию вы ожидаете?


Что угодно, но не обидные издёвки (подозреваю, что автор Lispin просто не ожидал таких наездов):

Who are you? Some kind of comedian?

I love how it says "Lisp without parentheses" yet the example contains several
of these damned things Nice post, btw: I laughed after just reading the
title.

All in all, this project has less value than a single useful Lisp macro.

the friendly community prevents Bill from doing stupid things, spending his
time on a bullshit. if he wants a better readability, he'd better write an
editor.

Did I say "user"? PWUAHAHHAHAHAHHAAH.... I meant self-important
dilettante. "Hey, guys! Just found Lisp! Love it! Here is how we can fix
it...your thoughts?" PWUAUUAUAUAUAHAHAHAHH... I slay myself.

Последний меня вообще порадовал.


LCR>>Суть сводится к следующему: профессионалы глядя на S-выражение видят сразу дерево, поэтому они не видят скобок!

CU>Я бы заменил "не видят" на "не замечают (пока парность не нарушается, но об этом заботится редактор, компилятор ругается)"
Ну хорошо, пусть так. +1


CU>Продолжение будет?

Будет день — будет пища.
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: Lisp без скобок
От: Oyster Украина https://github.com/devoyster
Дата: 05.12.06 15:55
Оценка: +1
Здравствуйте, cl-user, Вы писали:

CU>... И остаётся вопрос (тот-же ,что и к немерлистам) — получив body (блок кода) — я могу его расчленить, проанализировать отдельные части, и собрать из разных частей другой (новый — как угодно) блок кода?


Отвечу про Nemerle — можешь. В макрос тебе приходит AST, на выход ты выдаёшь другое AST. А внутри собераешь результирующее AST из исходного как душе угодно.
Re[3]: Lisp без скобок
От: Oyster Украина https://github.com/devoyster
Дата: 05.12.06 16:00
Оценка:
Здравствуйте, Oyster, Вы писали:

O>Отвечу про Nemerle — можешь. В макрос тебе приходит AST, на выход ты выдаёшь другое AST. А внутри собераешь результирующее AST из исходного как душе угодно.


Упс... читать "собираешь"
Re: Lisp без скобок
От: Sheridan Россия  
Дата: 06.12.06 08:31
Оценка: +2
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Наверное самый шикарный результат — это плагин color-box для Emacs:



Гм... У меня все чаще и чаще появляется желание бросить все, и засесть за изучение Emacs...

[RSDN@Home][1.2.0][alpha][668]
[Дурак — это человек, считающий себя умнее меня. [С. Лец]]
Matrix has you...
Re[3]: Lisp без скобок
От: cl-user  
Дата: 06.12.06 08:44
Оценка: +1
Здравствуйте, Oyster, Вы писали:

O>Отвечу про Nemerle — можешь. В макрос тебе приходит AST, на выход ты выдаёшь другое AST. А внутри собераешь результирующее AST из исходного как душе угодно.


Да, я уже увидел большинство интересовавшего меня в статье про макросистему немерле. Спасибо! Очень жаль, что нет полной тех. документации на всё это богатство
Re[2]: Lisp без скобок
От: Курилка Россия http://kirya.narod.ru/
Дата: 06.12.06 09:19
Оценка: +2 :))
Здравствуйте, Sheridan, Вы писали:

S>Гм... У меня все чаще и чаще появляется желание бросить все, и засесть за изучение Emacs...


Ну зачем совсем всё-то бросать?
Всёж он позволяет кое-какие вещи делать
Re[4]: Lisp без скобок
От: Oyster Украина https://github.com/devoyster
Дата: 06.12.06 09:39
Оценка:
Здравствуйте, cl-user, Вы писали:

CU>Да, я уже увидел большинство интересовавшего меня в статье про макросистему немерле. Спасибо! Очень жаль, что нет полной тех. документации на всё это богатство


Согласен — с доками есть определённая проблема (точнее, их почти нет ). На первое время спасают статьи на их сайте (+ некоторые переводы на RSDN), ну а потом лучшая дока — исходники компилятора.
Re[3]: Lisp без скобок
От: Sheridan Россия  
Дата: 06.12.06 10:10
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Ну зачем совсем всё-то бросать?

Чтобы время выделить

К>Всёж он позволяет кое-какие вещи делать

Дык..

[RSDN@Home][1.2.0][alpha][668]
[Красивые рифмы нередко служат костылями хромым мыслям. [Г. Гейне]]
Matrix has you...
Re[5]: Lisp без скобок
От: cl-user  
Дата: 06.12.06 11:34
Оценка: +6
Здравствуйте, Oyster, Вы писали:

O>Согласен — с доками есть определённая проблема (точнее, их почти нет ). На первое время спасают статьи на их сайте (+ некоторые переводы на RSDN), ну а потом лучшая дока — исходники компилятора.


Это сойдёт для тех, кто ковыряется в языке. Для тех, кто захочет применить немерле как инструмент для производства (если такие найдутся ) это категорически неприемлемо
Re[3]: Lisp без скобок
От: Cyberax Марс  
Дата: 06.12.06 12:20
Оценка:
Курилка wrote:
> S>Гм... У меня все чаще и чаще появляется желание бросить все, и засесть
> за изучение Emacs...
> Ну зачем совсем всё-то бросать?
> Всёж он позволяет кое-какие вещи делать
Я бросил Emacs после того, как заметил, что после установки нескольких
плугинов, Emacs стал занимать 90Мб (больше чем Студия!!!)
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[4]: Lisp без скобок
От: Курилка Россия http://kirya.narod.ru/
Дата: 06.12.06 12:31
Оценка: :))
Здравствуйте, Cyberax, Вы писали:

C>Я бросил Emacs после того, как заметил, что после установки нескольких

C>плугинов, Emacs стал занимать 90Мб (больше чем Студия!!!)

Eight Megabytes & Constantly Swapping ?
Re: Lisp без скобок
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 08.12.06 12:15
Оценка: 6 (2)
Дополнение.

Ещё есть динамический вариант емаксовского колорбокса.

http://community.schemewiki.org/?call-with-current-continuation

Лопата — в листингах. Поводите над ними мышой

PS: спасибо mishaa
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[2]: Lisp без скобок
От: frogkiller Россия  
Дата: 08.12.06 12:43
Оценка: +1
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR>Лопата — в листингах. Поводите над ними мышой


В IE6 не работает хорошо, что firefox стоит.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[3]: Lisp без скобок
От: frogkiller Россия  
Дата: 11.12.06 16:02
Оценка: 1 (1) :)
Вот, может, кому пригодится. Форматирует кусок кода на lisp для используемой там css.

// SchemeColorer.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>

bool isSpace(char ch) {    return ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t'; }
bool isDelimeter(char ch) { return ch == '(' || ch == ')' || isSpace(ch); }

const char *findmatched(const char *str, const char *fin)
{
    const char *tmp = str;
    for (int cnt = 1; tmp != fin && cnt > 0; ++tmp)
    {
        if (*tmp == '(') { ++cnt; }
        if (*tmp == ')') { --cnt; }
    }
    return tmp;
}

const char *findword(const char *str, const char *fin)
{
    for (const char *tmp = str; tmp != fin; ++tmp) if (isDelimeter(*tmp)) return tmp;
    return fin;
}

const char *skipspace(const char *str, const char *fin)
{
    for (const char *tmp = str; tmp != fin; ++tmp) if (!isSpace(*tmp)) return tmp;
    return fin;
}

std::string process_body(const char *str, const char *fin)
{
    if (str == fin)    return "";
    if (*str == '(')
    {
        const char *tmp = findmatched(str + 1, fin);
        std::string tmpres = std::string("<span class=\"paren\">(") + process_body(str + 1, tmp - 1) + std::string(")</span>");
        return tmpres + process_body(tmp, fin);
    }
    std::string res = "";
    const char *tmp1 = skipspace(str, fin);
    if (tmp1 != str) { res += std::string(str, tmp1); }
    const char *tmp2 = findword(tmp1, fin);
    if (tmp2 != tmp1)
    {
        res += std::string("<span class=\"scheme-documentation\">") + std::string(tmp1, tmp2) + std::string("</span>");
    }
    const char *tmp3 = skipspace(tmp2, fin);
    if (tmp3 != tmp2) { res += std::string(tmp2, tmp3); }
    return res + process_body(tmp3, fin);
}

std::string process(const char *str, const char *fin)
{
    return std::string("<pre class=\"scheme\">") + process_body(str, fin) + std::string("</pre>");
}

long getFileSize(FILE *f)
{
    long cur = ftell(f); fseek(f,0,SEEK_END);
    long len = ftell(f); fseek(f,cur,SEEK_SET);
    return len;
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (argc < 3)
    {
        std::cout << "usage: schemecolorer in.sch out.txt";
    }

    FILE *g_in = fopen(argv[1], "rb");
    if (!g_in)
    {
        std::cout << "cannot open source file " << argv[1] << std::endl;
        return -1;
    }

    FILE *g_out = fopen(argv[2], "wb");
    if (!g_out)
    {
        fclose(g_in);
        std::cout << "cannot open destination file " << argv[2] << std::endl;
        return -2;
    }

    long len = getFileSize(g_in);

    char *buffer = new char[len + 1];
    fread(buffer, sizeof(char), len , g_in);
    buffer[len] = '\0';

    std::string result = process(buffer, buffer + len).c_str();
    fwrite(result.c_str(), sizeof(char), result.length(), g_out); fflush(g_out);

    delete [] buffer;
    fclose(g_in); fclose(g_out);

    return 0;
}
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[4]: Lisp без скобок
От: frogkiller Россия  
Дата: 12.12.06 10:28
Оценка:
Здравствуйте, frogkiller, Вы писали:

По поводу "+", мда, действительно, как-то не подумал. Здесь у большинства читающих на написание такого уйдёт минут 5, причём на более подходящем для этого языке.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
Re[5]: Lisp без скобок
От: Lazy Cjow Rhrr Россия lj://_lcr_
Дата: 12.12.06 17:00
Оценка: :)
frogkiller,

F>По поводу "+", мда, действительно, как-то не подумал. Здесь у большинства читающих на написание такого уйдёт минут 5, причём на более подходящем для этого языке.


Ну думаю чуть больше (всё же C++ ), но вот я напрягал фантазию, что с этим кодом можно делать, но так и не придумал. Ну просто полюбовался на форматирование. Предположил, что FILE* ты наверное использовал, потому что iostream тормозит...
quicksort =: (($:@(<#[),(=#[),$:@(>#[)) ({~ ?@#)) ^: (1<#)
Re[6]: Lisp без скобок
От: frogkiller Россия  
Дата: 13.12.06 12:59
Оценка:
Здравствуйте, Lazy Cjow Rhrr, Вы писали:

LCR> Предположил, что FILE* ты наверное использовал, потому что iostream тормозит...


Просто потому что скопипастил с какого-то старого проекта. А ещё потому, что изначально алгоритм был ориентирован на указатели (читай, итераторы), а stream требует несколько другого подхода, всё равно пришлось бы считывать файл целиком.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Курица — это инструмент, с помощью которого одно яйцо производит другие.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.