Pull to refresh

Comments 16

Вопрос: зачем намеренно ограничивать себя? Если выбрали lisp/schema подобный синтаксис то почему бы не воспользоваться существующими библиотеками для этого? Некоторые из перечисленных ниже «java schema/lisp» библиотек хорошо интегрируются во внешние приложения.

1. Сlojure
2. JScheme
3. JLLL
4. Kawa
5. Помню была отличная библиотека skij от IBM, но что-то сейчас концов не нахожу…

Если замыкания, лямбда и прочее не нужно, то не факт что не понадобится…
Три причины:

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

За список библиотек, безусловно, спасибо
Partial quotes или макросы, имхо, позволили бы все 3 пункта покрыть. А они есть в любой более-менее серьезной реализации scheme/lisp на java.

Но если хочется просто попрактиковаться в реализации интерпретатора «языка-первопроходца», то тогда причины полностью понятны и поддерживаю!:)
Хочется не столько попрактиковаться, сколько построить прототип языка, максимально приспособленного именно для этой задачи. Речь не идёт о разработке ещё одного универсального языка.
Мне кажется с языком не всё в порядке
(link (name forward)  (J1 J2) (A2 A3) (K3 K3))

link и name — имена функций. forward, J2, A3 и вторая K3 — вроде как константы или какие-то литералы. А чем являются J1, A2 и первая K3? И как их отличить от имен функций? Такие «шероховатости» в языке могут принести столько проблем, что поседеете.
Я понимаю, о чём вы говорите, но, к счастью, всё не так плохо. Скрипт состоит из двух частей. Условно их можно назвать декларативной и императивной. Декларативная часть заключена в тэги «game» и «variant», императивная — набор define-ов, используемых в декларативной, и описывающих особенности выполнения хода (возможно сложные). Теперь рассмотрим по порядку, что, из того что вызывает вопросы, есть что:

link — декларативная конструкция, которая может встречаться лишь в описании board (части описания game), в строго определённом месте
name — тэг который может встречаться в некоторых декларативных конструкциях (таких как link или zone)
forward — псевдопеременная, которая должна определяться в board как направление и может использоваться в императивной части (не литерал!)
J2, A3,… — тоже псевдопеременные, но определяющие позиции на доске (может быть определена явно или как часть grid-а)

Соответсвенно, link и name от функций отличать не надо, поскольку они не используются там где используются функции. Можно даже определить одноименные функции в скрипте и эо не приведёт к ошибкам (хотя и запутает код). Направления и позиции, в императивном коде, отличать от функций необходимо, но делается это просто. Если имя определено в том board, который используется в настоящий момент (доступно через Environment) — это определения доски (псевдопеременные), в противном случае, ищем определения функций с такими именами в скрипте (если их нет — ошибка).

Этот подход выдуман не мной (я лишь постарался сделать его гибче) и успешно используется в ZRF с 2005 года. Если бы речь шла об универсальном языке, подобное было бы недопустимо, но, в данном случае, речь идёт о языке, ориентированном на одну узкую задачу — описание правил настольных игр
1) Основные функции, которые хотелось бы видеть для подобного языка, это
— модифицирование функций/значений и замена

// base board
(board
   (pieses....)
)

.....

(board
    (previous board)
)


2) В Хаскеле есть замечательное свойство писать имена функций только с маленькой буквы, а конструкторы — с большой.

Если в этом лисп-подобном языке есть затруднения, переменная это или значение — можно использовать первую большую букву для «значений».

(piece-move North)


3) Так же можно добавить и переменные переменных (в терминах ПХП). Например, обратный апостроф:

`(add "No" "rth")   ===   North

`(`(add "a" "dd") "No" "rth")  ===  North
1) «Наследование» структур с возможностью их переопределения бывает полезно и в настоящий момент частично реализовано конструкцией variant (к сожалению, не так полно как хотелось бы). Я всё ещё думаю над этим
2) Codestyle ещё предстоит выработать, спасибо за совет
3) Вот это я пока не могу сообразить где могло бы быть полезным. На мой взгляд, такая возможность просто всё запутает
На счёт (3), можно элементарно релизовать например функцию имени клетки:
(define (getCell row col) `(add row col))

(getCell "A" "8")  ===  A8


или функцию действия
(define move_attack ....)
(define move_swim   ....)

(`(add "move_" action) figure)


Зачастую подобная фича излишня, но порой способно сэкономить код и сделать его более выразительным.
Да, возможно я поторопился. В некоторых случаях это может быть полезным.
Обратите внимание на tcl, он конечно не совсем лисп-подобный, но остальным вашим требованиям думаю отвечает. Вы можете сами создать дочерний safe интерпретер, и экспортировать в него только разрешенные вами функции… Он довольно легко встраивается куда хочешь, биндинги tcl -> anything -> tcl и наоборот строятся очень просто.

А запись будет выглядеть как-то так, вместо:
(board 
   ...
   (link (name forward)  (J1 J2) (A2 A3) (K3 K3))
   ...
)

Будет:
[board 
   ...
   [link [name forward]  [J1 J2] [A2 A3] [K3 K3]]
   ...
]

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

Например, вот это родной цикл foreach:
set k 0
foreach {n v} {1 "abc" 2 "def"} {
  puts [format "%i, %-2s: %s" $k $n $v]
  incr k
}
puts "last: $k, $n"

0, 1 : abc
1, 2 : def
last: 2, 2

A вот это собственноручно сделанный цикл my-foreach:
proc my-foreach {vars lst code} {
  puts "... start ..."
  foreach _(v) $vars { upvar $_(v) $_(v) }
  foreach $vars $lst {
    puts "  ... before ..."
    uplevel $code
    puts "  ... after ..."
  }
  puts "... end ..."
}

my-foreach {n v} {10 "abc" 11 "def"} {
  puts [format "%i, %-2s: %s" $k $n $v]
  incr k
}
puts "last: $k, $n"


... start ...
  ... before ...
2, 10: abc
  ... after ...
  ... before ...
3, 11: def
  ... after ...
... end ...
last: 4, 11

Да, я знаю про tcl, хороший язык
Тогда тем более жутко интересно узнать, чем он вас, применительно к этой задаче, не устроил?
Особенно учитывая ваш вот этот коммент.
Тем, что я не хочу связывать себя сейчас концепциями или идиомами какого либо из существующих языков.
Когда все задумки по проекту в голове устаканятся, я посмотрю не подходит ли для этого какой либо язык (например TCL).
Напомнило мне один недавний случай. Диалог с одним разработчиком… (вольный пересказ):
Я: Следуй REST. Регистрация нового клиента — POST на /users, редактирование старого — PUT на /users/42

ОН: Да нафига такие сложности, я уже сделал POST, если в базе есть юзер с таким id то это обновление, а если нет, то регистрация нового. Все же просто.

Я: REST уже описан, а твой подход, назовем его «Как сказал Вася», неизвестен никому, даже тебе. Как ты будешь работать с заявками на сервере? Что тебе придется придумывать в «Как сказал Вася» чтобы работать с заявками. Кто это будет документировать?

ОН: Ну в заявках я буду использовать REST!

Я: Ок. Какая из систем проще, та, в которой везде используется REST, или та, в которой где-то используется REST, а где-то «Как сказал Вася»?

ОН: Я всё равно считаю, что мой подход проще!

Я: ?!

Напомнило мне одну цитату (по моему из одной из книжек Айсберга):

Остерегайтесь необдуманных аналогий...
Sign up to leave a comment.

Articles