LINUX.ORG.RU

Ответ на: комментарий от realsmart

;; предварительная CL версия порт с adv_server.py

(require "comm")

(defmacro defstruct! (name &rest slots)
  `(progn (defstruct ,name ,@slots)
     (defmacro ,(intern (format nil "WITH-~D" (string-upcase name))) ((w) &body body) 
          `(with-slots ,',slots ,w ,@body))))

(defstruct! world
   map h items pocket px py dirty)

(defmacro ref2d (array-of-arrays pos)
  `(aref (aref ,array-of-arrays (imagpart ,pos)) (realpart ,pos)))

(defmacro set2d! ((array-of-arrays pos) v)
  `(setf (aref (aref ,array-of-arrays (imagpart ,pos)) (realpart ,pos)) ,v))

(defconstant *moves* `("north" #C(0 -1) "south" #C(0 1) "east" #C(1 0) "west" #C(-1 0)))

(defun start-server (world-file port)
  (with-open-file (in world-file :direction :input)
    (let ((w (make-world)))
      (with-world (w)
       (loop for line = (read-line in nil nil)
             for lidx fixnum from 0 while line
             for p = (position #\. line)
             collect line into lines
             finally (setf map (make-array (length lines) :initial-contents lines))
             when p do (setf pos (complex p lidx))
                       (incf items (count #\$ line))
       (flet ((world-service-server (handle)
                (let ((stream (make-instance 'comm:socket-stream
                                     :socket handle                               
                                     :direction :io                               
                                     :element-type 'base-char)))
                  (mp:process-run-function "World" () 'connect-n-serve stream w))))

        (comm:start-up-server :function 'connect-n-serve :service port)))))))
  

(defun connect-n-serve (stream world)
  (with-world (world)
    (print "; Welcome to dark dungeon.~%
; Available commands: world, north, south, east, west, pickup, drop\~%" stream)
    (loop for command = (read-line stream nil 'eof) 
          until (eq command 'eof)
          for dir = (assoc command *moves*)
          for floor = (ref2d world pos)
          do (cond (dir ;; command is direction
                    (let ((npos (+ dir pos)))
                      (cond ((and (> (length map) (imagpart npos))
                                  (>= (length map) 0) (>= (realpart npos) 0)
                                  (not (eql (ref2d map npos) #\#)))
                               (set2d! (dirty pos) floor)
                               (set2d! (dirty npos) floor)
                               (setf pos npos))
                            (t (print "Illegal move!" stream)))))
                   ((equalp command "pickup")
                    (cond ((and (not pocket) (eql floor #\$))
                              (set2d! (world pos) #\space)
                              (setf pocket t))
                          (t (print "Can not pickup!" stream))))
                   ((equalp command "drop")
                    (cond ((and pocket (not (eql floor #\$)))
                              (setf pocket nil)
                              (if (eql floor #\.)
                                  (if (zerop (decf items)) (print "You win!" stream))
                                  (set2d! (world pos) #\$)))
                          (t (print "Can not drop!" stream))))
                   ((equalp command "world")
                        (loop for l across map do (print l stream)))
                   (t (print "Unknown command!" stream)))
              (print "OK" stream))))

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

>Вопрос: она поддерживает уровни трассировки и сложные команды (подпрограммы)?

Пардоньте, что именно означает "уровни трассировки"? И нафи^W для чего это нужно на практике?

А "сложные команды (подпрограммы)", если я правильно это понимаю, поддерживаются. Т.е. клиент может отправить сразу N различных команд и сервер выполнит их последовательно. Собственно, так робот и работает.

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

> Пардоньте, что именно означает "уровни трассировки"?

Различные уровни детализации вывода.

> И нафи^W для чего это нужно на практике?

> Т.е. клиент может отправить сразу N различных команд и сервер выполнит их последовательно. Собственно, так робот и работает.

Клиент может работать, как минимум, двумя разными способами. Один способ -- это когда он отправляет сразу всю серию команд на сервер, а после отработки показывается только результат работы. Другой способ -- это когда робот отправляет на сервер команду за командой, и после каждой команды показывать состояние мира. В моем варианте на Лиспе это записывается двумя разными способами, например:

((go-west go-west go-west))

и

((go-west) (go-west) (go-west))

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

Для робота может быть полезно записать три уровня вложенности -- для всей программы целиком, для демонстрации в точках подъема предметов и после каждого шага. Соответственно, можно задать три уровня трассировки. Правда, сейчас у меня робот всегда формирует программу только для самого детального уровня, как это требуется в условии, хотя сначала он у меня работал на нулевом уровне. Это, кстати, усложнило программу.

Еще, может быть, есть смысл ввести команду show-world, чтобы задавать явно точки отображения мира. И заодно разрешить использовать в программе метакоманду autocollect, которая разворачивается в соответствующую подпрограмму. А отсюда уже один шаг к именованным подпрограммам. Метакоманду quit можно дополнить метакомандами return, которая выходит из текущей подпрограммы, и exit, которая завершает выполнение подпрограмм и выходит на заданный уровень вложенности или вообще завершает выполнение. Добавьте сюда условное исполнение и цикл, и получите уже достаточно мощный DSL управления роботом, типа Лого или Lua.

Вот такая вот практическая полезность...

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

> Не уверен, что в этой части что-то понадобится менять, поэтому просто > "свернул" пару функций :)

(or (< (realpart point) 1) (> (realpart point) (bound-x world)) (< (imagpart point) 1) (> (imagpart point) (bound-y world)) (member point (wall-points world)))

:-)))

> Раскрыть в объявлении констант pairlis - помимо экономии слова, > имхо, нагляднее

Я пробовал, но оно у меня ругнулось, когда я попробовал применить к такому списку assoc. Я думал, ассоциативные списки делаются только специальными функциями. Дома проверю.

> (defconstant +directions+ ..

А в чем сакральный смысл плюсов в дефиниции? Если это соглашение по именам констант, то почему command-reversion сделано без них? И я еще видел переменные, окаймленные астериксами -- *blah* -- что это значит? И вообще, есть ли соглашения по кодированию и стилю программ на Лиспе и где об этом можно почитать?

> 3. Мелкие исправления

Понятно, для меня это вообще проблема -- отличить место, где есть неявный progn. Очень часто пытаюсь применить его в теле функции, кажется, так нельзя? По крайней мере, было несколько странных эффектов, с тех пор стараюсь, когда сомневаюсь, указывать progn явно или вообще пользоваться cond. Про (if (null x) () ...) -- хотел показать, что основой рекурсии является пустой список.

> Многострочные setf

Просто не знал :-). Получается, что для атомарных имен setf ничем не отличается от setq, но позволяет писать несколько присваиваний? Почему такой возможности нет у setq?

> 5. От одного eval можно легко избавиться (но это как раз увеличивает код

Каюсь, именно в этом месте погнался за оптимизацией.

> +(def-commands #.+directions+)

Что делает #.? Насколько я знаю, хэш означает блокировку, для чего она в этом случае?

eugine_kosenko ★★★
()

Кстати, тут пару десятков страниц назад затрагивали тему рефакторинга. Как раз споткнулся об это дело в Лиспе. Сначала программа использовала глобальные переменные, а затем появилась структура. Пришлось везде заменять на обращения к атрибутам. Теперь предстоит заменить обращения к атрибутам на вызов методов.

Вторая задача -- переименование. Суть в том, что после компиляции лисп-программа уже является некоторым связаным деревом. Было бы интересно поиметь некую волшебную функцию (defun rename (funname)), которая заменяла бы имя функции в дереве, а потом декомпилировать в исходный код. Кстати, для Лиспа есть декомпиляторы?

Я так подумал, что часть задач рефакторинга можно решать на самом Лиспе, потому как программы на нем им же и могут обрабатываться. Но тут вся загвоздка в pattern-matching, например, должна быть некая функция like, которая бы выдавала истину для такого, например, выражения:

(like '((a b) c) '(d e))

то есть, выполняла бы поиск гомоморфизмов на деревьях. А если бы к этому еще работал и биндинг а-ля Пролог (то есть, после выполнения символ d содержал список (a b)), то это была бы вообще прелесть. Может быть, это equalp делает? Я просто еще не разобрался в его семантике.

В общем, есть что-нибудь пользительное для анализа кода на Лиспе?

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

>Клиент может работать, как минимум, двумя разными способами. Один способ -- это когда он отправляет сразу всю серию команд на сервер, а после отработки показывается только результат работы. Другой способ - это когда робот отправляет на сервер команду за командой, и после каждой команды показывать состояние мира. В моем варианте на Лиспе это записывается двумя разными способами.

А... это... и всего-то, конечно можно. Давайте вспомним постановку задачи, там чётко задана команда сервера "world", которая присылает текущее состояние мира. Так вот, мой сервер и клиент не делают лишних (ненужных) телодвижений, а просто используют установленный протокол. Короче, чтобы обеспечить "максимальный уровень трассировки" клиент после каждой команды движения посылает команду "world", причём не для себя, а для человека за монитором, чтобы ему удобно рассматривать было. Вот так сейчас и сделано. Если убрать эти "лишние" world -- моя программа станет на пару слов короче.

В общем, у меня сам клиент решает, когда показать состояние мира человеку. Например, тривиальным образом (одно слово переместить) я могу сделать отображение мира только в момент подъёма/опускания. Могу показывать мир только по четвергам ночью в полнолуние ;)

А вот на счёт последнего Вашего абзаца... Вы уж меня извините, но какая-то белиберда бесполезная... Сплошные лишние сущности. Это всё реализуется проще, даже не выходя за рамки стандартного протокола.

Вот такая вот практическая полезность. ;)

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

добавка к предидущему сообщению:

под последним параграфом я имел в виду вот этот текст:

>Еще, может быть, есть смысл ввести команду show-world, чтобы задавать явно точки отображения мира. И заодно разрешить использовать в программе метакоманду autocollect, которая разворачивается в соответствующую подпрограмму. А отсюда уже один шаг к именованным подпрограммам. Метакоманду quit можно дополнить метакомандами return, которая выходит из текущей подпрограммы, и exit, которая завершает выполнение подпрограмм и выходит на заданный уровень вложенности или вообще завершает выполнение. Добавьте сюда условное исполнение и цикл, и получите уже достаточно мощный DSL управления роботом, типа Лого или Lua.

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

> Потом опять же что-то вроде CELLS никак не сделать.

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

Когда зашла речь о CELLS, мои архаровцы тоже стали искать что-то похожее и таки нашли RETE для Oracle и еще какую-то поделку для .Net. Но менять технологию, похоже, уже поздно...

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

> Давайте вспомним постановку задачи, там чётко задана команда сервера "world", которая присылает текущее состояние мира.

Давайте вспомним, с чего вообще начался спор. Было указано, что Лисп начинает показывать свои преимущества только на достаточно крупных задачах, потому как на программах класса "Hello, world" он даже хуже, чем другие быд^Wязыки.

> Так вот, мой сервер и клиент не делают лишних (ненужных) телодвижений, а просто используют установленный протокол.

Увы, в реальном мире системам свойственно эволюционировать, и даже аппеляция к согласованному и подписанному техническому заданию при спорах с заказчиком не всегда спасает. Речь идет о том, что на Лиспе проще писать программы, способные эволюционировать в соответствии с усложнением требований предметной области. Опять же, задача была выбрана, чтобы показать преимущества развивающегося DSL. По-моему, это было отлично продемонстрировано.

Открою по секрету, что небольшое изменение лисп-программы позволит роботу исполнить удаленно _любую_ лисп-программу, в том числе с ветвлениями и циклами. То есть, простота DSL тут вяжется с встроенной мощью Лиспа, о чем тоже говорили вначале.

Я бы даже сказал так, что многие фичи лисп-программ очень часто получаются исключительно как "побочный продукт" решения основной задачи. То есть, вроде бы и не собирался наделять программу этим свойством, и вдруг обнаруживаешь, что она и так может. Кайфовое ощущение :-). Нужно просто немножко отойти от парадигмы программирования "под заказ" :-).

> клиент после каждой команды движения посылает команду "world", причём не для себя, а для человека за монитором, чтобы ему удобно рассматривать было.

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

> В общем, у меня сам клиент решает, когда показать состояние мира человеку.

Когда компьютер начинает принимать решения за человека, то получается техноужыс вроде терминаторов, матриц и прочих оффтопиков XP ;-). Лично я люблю сам определять уровень получаемой информации.

> Могу показывать мир только по четвергам ночью в полнолуние ;)

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

> А вот на счёт последнего Вашего абзаца... Вы уж меня извините, но какая-то белиберда бесполезная... Сплошные лишние сущности.

Хум хау. Кому и станки с ЧПУ -- это сплошные лишние сучности. Однако в жизни обычно чаще бывает наоборот...

> Это всё реализуется проще, даже не выходя за рамки стандартного протокола.

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

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

> Как-то оно там крововато выглядит... (кто-то чать буковок съел)

Мнэ, сейчас посмотрел на исходник внимательнее, таки в самом деле вака сожрала пару скобок. У нее это элемент разметки.

Вот, кстати, вопрос -- боевая раскраска в виках. Для Питона есть, для Java есть, даже для Эйфеля есть, а для Лиспа не сподобились сделать.

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

* (require "comm")

debugger invoked on a SB-INT:EXTENSION-FAILURE: Don't know how to REQUIRE comm. See also: The SBCL Manual, Variable *MODULE-PROVIDER-FUNCTIONS* The SBCL Manual, Function REQUIRE

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name): 0: [ABORT] Exit debugger, returning to top level.

(SB-IMPL::REQUIRE-ERROR "Don't know how to ~S ~A.") 0]

Где брать и как настроить?

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

Где взять, я не посмотрел, а настроить просто. В sbcl -- исходник, в .sbcl/systems -- ln -s на .asd. Для sbcl этот линк -- доступность пакета. Тогда require видит его без всяких вопросов.

Еслиты тестируешь программы на разных лиспах, и если лисп поддерживается common lisp controller, то лучше положить все программы в каталог, скажем, ~/cl, создать ~/.clc/systems и по аналогии с sbcl наделать линков на *.asd. Тогда исходники увидит много лиспов.

(clc:clc-require :package-name).

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

> 2. Раскрыть в объявлении констант pairlis - помимо экономии слова, имхо, нагляднее

Понял, почему у меня не пошел экспериментальный пример. Я писал

'((1.2) (3.4))

и оно приняло точечную пару за число с плавающей точкой. :-(

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

> 2. Раскрыть в объявлении констант pairlis - помимо экономии слова, имхо, нагляднее

Понял, почему у меня не пошел экспериментальный пример. Я писал

'((1.2) (3.4))

и оно приняло точечную пару за число с плавающей точкой. :-(

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

> В sbcl -- исходник, в .sbcl/systems -- ln -s на .asd.

Ну, это мы уже проходили. Вопрос в том, на что именно линк. Я такого пакета вообще не нашел.

> Если ты тестируешь программы на разных лиспах, и если лисп поддерживается common lisp controller

Тут бы один освоить...

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

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

>Ну, это мы уже проходили. Вопрос в том, на что именно линк. Я такого пакета вообще не нашел.

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

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

Ну вот, новая версия на OCaml, сократил немного за счет логики и за счет
ввода/вывода. Теперь получается 114 непробельных (порой довольно длинных)
строк.

[Makefile]
adventure: advserver hclient roboclient

advserver: adv_world.cmo advserver.ml
	ocamlc unix.cma adv_world.cmo advserver.ml -o advserver
hclient: adv_world.cmo hclient.ml
	ocamlc -g unix.cma adv_world.cmo hclient.ml -o hclient
roboclient: adv_world.cmo roboclient.ml
	ocamlc -g unix.cma adv_world.cmo roboclient.ml -o roboclient
adv_world.cmo: adv_world.mli adv_world.ml
	ocamlc -g -c adv_world.mli
	ocamlc -g -c adv_world.ml

clean:
	rm -Rf *~ *.cm[io] advserver hclient roboclient 

[adv_world.ml]
let find map c =
  let rec find_aux i =
    if i = Array.length map then raise Not_found
    else try (i, String.index map.(i) c) with Not_found -> find_aux (i + 1)
  in find_aux 0

let get_items map =
  let rec get_items_aux accu = function
      (i, j) when i = Array.length map      -> accu
    | (i, j) when j = String.length map.(i) -> get_items_aux accu (i + 1, 0)
    | (i, j) -> get_items_aux (if map.(i).[j] = '$' then (i, j) :: accu else accu) (i, j + 1)
  in
  get_items_aux [] (0, 0) ;;

let num_of_items map = List.length (get_items map) ;;

let input ic =
  let rec input_aux () =
    try let line = input_line ic in line :: input_aux () with End_of_file -> []
  in
  Array.of_list (input_aux ())

let gen_map map ((x, y), _) =
  let map' = Array.map (function line -> String.copy line) map in
  map'.(x).[y] <- '@' ; map'

let gen_stat map ((x, y), is_empty) =
    [ if num_of_items map = 0 && is_empty then "You won!" else "Game is in progress";
      if is_empty then "Your hand are empty" else "You carry an item";
      if map.(x).[y] = '$' then "Here lies 1 item" else "Here lies 0 items" ]

[adv_world.mli]
val find : string array -> char -> int * int
val get_items : string array -> (int * int) list
val num_of_items : string array -> int
val input : in_channel -> string array
val gen_map : string array -> (int * int) * 'a -> string array
val gen_stat : string array -> (int * int) * bool -> string list 

[advserver.ml]
let serve_cmd map ((x, y), is_empty) = function
    "pickup" when is_empty && map.(x).[y] = '$' ->
      map.(x).[y] <- ' ' ;
      ((x, y), false)
  | "drop" when not is_empty && map.(x).[y] <> '$' ->
      if map.(x).[y] <> '.' then map.(x).[y] <- '$' ;
      ((x, y), true)
  | cmd ->
      let cmds = [("north", (-1, 0)); ("south", (1, 0)); ("west", (0, -1)); ("east", (0, 1))] in
      let x', y' = (fun (dx, dy) -> x + dx, y + dy) (try List.assoc cmd cmds with Not_found -> 0, 0) in
      (if (try ignore map.(x).[y]; false with Invalid_argument _ -> true) || map.(x').[y'] = '#' then x, y else x', y'), is_empty

let serve in_channel out_channel =
  let map = Adv_world.input (open_in Sys.argv.(1)) in
  let rec loop state =
    Marshal.to_channel out_channel (Adv_world.gen_map map state) [] ;
    Marshal.to_channel out_channel (Adv_world.gen_stat map state) [] ;
    flush out_channel ;
    try
      let state = serve_cmd map state (input_line in_channel) in
      loop state
    with
      End_of_file -> ()
  in
  loop ((Adv_world.find map '.'), true) ;;

Unix.establish_server serve (Unix.ADDR_INET (Unix.inet_addr_loopback, int_of_string Sys.argv.(2))) ;; 

[hclient.ml]
let in_channel, out_channel = Unix.open_connection
  (Unix.ADDR_INET ((Unix.inet_addr_of_string Sys.argv.(1)), int_of_string Sys.argv.(2)))
in
while true do
  Array.iter (Printf.printf "%s\n") (Marshal.from_channel in_channel : string array) ;
  List.iter (Printf.printf "%s\n") (Marshal.from_channel in_channel : string list) ;
  flush stdout ;
  Printf.fprintf out_channel "%s\n" (read_line ()) ;
  flush out_channel
done ;;

[roboclient.ml]
let dfs map (sx, sy) =
  let dxy = [(-1, 0); (1, 0); (0, -1); (0, 1)] in
  let f = Array.init (Array.length map) (function i -> Array.make (String.length map.(i)) (-1)) in
  let q = Queue.create () in
  Queue.push (sx, sy) q ; f.(sx).(sy) <- 0 ;
  while not (Queue.is_empty q) do
    let x, y = Queue.pop q in
    List.iter
      (fun (x', y') -> Queue.push (x', y') q ; f.(x').(y') <- f.(x).(y) + 1)
      ( List.filter
          (fun (x', y') -> (try ignore map.(x').[y']; true with Invalid_argument _ -> false) && map.(x').[y'] <> '#' && f.(x').(y') = -1)
          (List.map (fun (dx, dy) -> x + dx, y + dy) dxy) )
  done ;
  f

let find_path f (x, y) =
  let rec find_path' (x, y) path rev_path =
    let dxy = [((-1, 0), ("south", "north")); ((1, 0), ("north", "south"));
               ((0, -1), ("east", "west")); ((0, 1), ("west", "east"))] in
    if f.(x).(y) = 0 then path @ ["pickup"] @ (List.rev rev_path) @ ["drop"] else
      let find_path_aux (dx, dy) (dir, rev_dir) =
        if try f.(x + dx).(y + dy) + 1 = f.(x).(y) with Invalid_argument _ -> false then
          find_path' (x + dx, y + dy) (dir :: path) (rev_dir :: rev_path)
        else []
      in
      List.fold_right (function (d, dirs) -> (function [] -> find_path_aux d dirs | path -> path)) dxy []
  in
  find_path' (x, y) [] []

let main () =
  let in_channel, out_channel = Unix.open_connection
    (Unix.ADDR_INET ((Unix.inet_addr_of_string Sys.argv.(1)), int_of_string Sys.argv.(2)))
  in

  let world = (Marshal.from_channel in_channel : string array) in
  Array.iter (Printf.printf "%s\n") world ;
  List.iter (Printf.printf "%s\n") (Marshal.from_channel in_channel : string list) ;

  let start = Adv_world.find world '@' in
  let marks = dfs world start in

  List.iter
    ( fun (x, y) ->
        List.iter
          ( fun cmd ->
              Printf.printf "\ncommand: %s\n" cmd ;
              Printf.fprintf out_channel "%s\n" cmd ;
              flush out_channel ;
              Array.iter (Printf.printf "%s\n") (Marshal.from_channel in_channel : string array) ;
              List.iter (Printf.printf "%s\n") (Marshal.from_channel in_channel : string list) )
          (find_path marks (x, y)) )
    ( Adv_world.get_items world ) ;;

main () ;;

Кстати, прошу заметить, что 6 лишних строк получается за счет файла
интерфейса adv_world.mli, ну и еще то, что у лидера не считаись
строки человеческого клиента (его нет).

satanic-mechanic
()
Ответ на: комментарий от yyk

> Есть несколько предложений, но пока "чисто косметических" - никаких
> изменений в алгоритме.

Все принял, но все никак не пойму, что делает #. В стандарте сказано,
что это read-time evaluation (я правильно понял?), но я не пойму, когда
это на самом деле вычисляется.

В любом случае, это все еще косметика:

Total length                                         1745
Meaning length                                        545
Total thesaurus                                       211
Meaning thesaurus                                     125
Total saturation (%)                                   31
Thesaurus saturation (%)                               59
Total expressiveness (%)                               12
Meaning expressiveness (%)                             23

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

> Для sbcl и cmucl надо использовать (require :sb-bsd-sockets). Но там
> уже функции другие.

* (asdf:operate 'asdf:load-op 'trivial-sockets)


; loading system definition from
; /usr/share/common-lisp/systems/trivial-sockets.asd into #<PACKAGE "ASDF0">
; registering #<SYSTEM TRIVIAL-SOCKETS {10027B7691}> as TRIVIAL-SOCKETS
; loading system definition from
; /usr/lib64/sbcl/sb-bsd-sockets/sb-bsd-sockets.asd into #<PACKAGE "ASDF0">
; registering #<SYSTEM SB-BSD-SOCKETS {1002A67B11}> as SB-BSD-SOCKETS

Похоже, я именно их и использую. Точнее, обертку в виде trivial-sockets.
Говорят, есть еще более высокая обертка, но не для SBCL/CMUCL.

eugine_kosenko ★★★
()
Ответ на: комментарий от satanic-mechanic

> Ну вот, новая версия на OCaml, сократил немного за счет логики и за > счет ввода/вывода. Теперь получается 114 непробельных (порой довольно > длинных) строк.

Total length 1396 Meaning length 461 Total thesaurus 159 Meaning thesaurus 106 Total saturation (%) 33 Thesaurus saturation (%) 67 Total expressiveness (%) 11 Meaning expressiveness (%) 23

Уже близко :-).

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

Total length                                         1396
Meaning length                                        461
Total thesaurus                                       159
Meaning thesaurus                                     106
Total saturation (%)                                   33
Thesaurus saturation (%)                               67
Total expressiveness (%)                               11
Meaning expressiveness (%)                             23

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

> Человек явно писал программу на LW.

Тады ой. Статистика явно хорошая:

Total length                                          325
Meaning length                                        120
Total thesaurus                                       105
Meaning thesaurus                                      72
Total saturation (%)                                   37
Thesaurus saturation (%)                               69
Total expressiveness (%)                               32
Meaning expressiveness (%)                             60

Однако по оценкам волновой алгоритм может довести длину примерно до 900. Это тоже хорошо, но где гарантия, что это работоспособно?

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

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

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

> Так Вы скажите, что сделать-то нужно, а?

Да успокойтесь Вы :-). Можете считать что на отдельно стоящей учебно-тренировочной задаче пока что Питон с Окамлем сделали Лисп :-).

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

Зря кипятитесь. В жизни оно так и бывает чаще всего: заказчик сам не знает, чего хочет, и только после пилота к нему внезапно приходит озарение, как нужно было сделать. Как пишется в одной умной книжке, "сначала проектируют как сарай, потом делают сарай, а внедряют уже как небоскреб". Щас тянем уже три таких "быдлопроекта" и на горизонте еще три отчетливо прописываются. А шо поделать -- это жизнь :-).

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

Вот и получается, что лично для себя я вынес понимание того, что такое DSL и как макросы могут существенно сократить код (в одном случае) и повысить функциональность (в другом). Вы, как я понял, вынесли понимание того, что Лисп сосет. Ну это уже suum quique :-).

Наконец, позволю себе заметить, что переход на личности слегка не красит оппонента. Вполне вероятно, что у Вас есть опыт написания сетевых приложений, который Вы успешно применили. Понятно, что я в этом вопросе сосунок по сравнению с Вами. С другой стороны, если бы взяли более близкую мне задачу синтаксического/лексического анализа, то все могло сложиться совсем по другому. Ведь аналог моей мерялки на Питоне я пока что не видел ;-).

Все это, как говорится, не флейма ради, а справедливости для...

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

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

Кстати, я только сейчас обратил внимание, что я для экстрима еще и экзотические структуры данных выбрал. Если в субботу пробьет, попробую портануть Ваш алгоритм на более классических структурах. Не боитесь, что программка на Лиспе и покороче может стать? ;-)

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

>(require "comm") >debugger invoked on a SB-INT:EXTENSION-FAILURE: Don't know how to >REQUIRE comm. See also: The SBCL Manual, Variable *MODULE-PROVIDER->FUNCTIONS* The SBCL Manual, Function REQUIRE

К сожалению я использую исключительно под Lispworks, модуль COMM под SBCL в том же виде не существует, там надо использовать trivial-scokets или usockets (последняя еще разрабытывается). Встроенная библиотека сокетов SBCL IMHO малость низкоуровневая. Не думаю, что возникнут какие-то проблемы с портированием сокетного кода на SBCL.

Код под Lispworks тем не менее является портабельным (в пределах Lispworks) и должен без изменений работать на WIN32,Linux,FreeBSD,MAC OS и UNIX (???), и скорее всего пойдет на 64 битной версии (Lispworks 5.0).

Lispworks Personal Edition (ограничения по времени работы и размеру хипа + нельзя делать EXEшники) - брать на http://www.lispworks.com/downloads/index.html

SBCL уважаю, но под винду он еще малость сыроват, может к концу года похорошеет.

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

>Однако по оценкам волновой алгоритм может довести длину примерно до >900. Это тоже хорошо, но где гарантия, что это работоспособно?

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

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

>В общем, есть что-нибудь пользительное для анализа кода на Лиспе?

Как минимум есть множество разношерстных codewalkers, теоретически их одних достаточно, чтобы заниматься переименованием и т.п. О рефакторинге на Лиспе вообще мало что слышно, то ли каждая контора тайком свой велосипед изобретает, то ли он вообще не нужен, не понятно.

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

>Можете считать что на отдельно стоящей учебно-тренировочной задаче >пока что Питон с Окамлем сделали Лисп :-).

OCaml скорей всего будет выполняться шустрее, но Питон в императивном стиле более краток. Лисп с оптимизациями наверняка приблизится к OCaml по всем параметрам.

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

Народ может кто шуканет сюда народ из fido7.ru.lisp? А то больно интересно читать, только примеров маловато.

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

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

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

> Было указано, что Лисп начинает показывать свои преимущества только на достаточно крупных задачах, потому как на программах класса "Hello, world" он даже хуже, чем другие быд^Wязыки.

Однако, никто это реальным опытом подтвердить не может. Ну кроме viaweb.com естественно (хотя есть и контрпример: reddit.com). Я тут спрашивал про реальные проекты на Лиспе, ни у кого не было крупных проектов на лиспе.

Т.е. преимущества лиспа проявляются только на крупных проектах, которых не существует :-)

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

> Да успокойтесь Вы :-). Можете считать что на отдельно стоящей учебно-тренировочной задаче пока что Питон с Окамлем сделали Лисп :-).

У меня есть предложение: пусть модераторы всем участникам контеста добавят по звезде за заслуги :-)

Порешим на том что победила дружба :-) И лисперы прекратят вопли про быдлоязыки, по типу этого:

Ибо воистину. Первый Язык, жемчужина посреди простых камней, и нет языков кроме Него. Скобки, в которых пустота - тело Его, мистическое двуединство кода и данных - дух Его, божественная рекурсия - сердце Его. Истинно говорю вам, избегающий света Его есть безумец, вот, свершается кара над главой его, и убогостью отмечены поделия его, подобные пустым глиняным горшкам рядом с хрустальным сосудом благодати Его. Принявший же и постигший истинный свет Его подобен прямой и отточенной стреле, чисты помыслы его и крепка рука его, и благословенны творения его, дарующие радость и утоляющие печали, ибо одухотворены духом Его и отмечены благодатью Его.

(это на lorquotes посылать не надо, это уже оттуда)

> Ведь аналог моей мерялки на Питоне я пока что не видел ;-).

Ну лично я вообще в синтаксическом анализе/разборе вообще ни в зуб копытом. Это узкоспецифическая задача.

redvasily
()
Ответ на: комментарий от satanic-mechanic

Очередная версия на питоне:

http://rapidshare.com/files/835926/advworld.rar.html

Добавлена возможность выполнения нескольких комманд за раз и комманда "autocollect". Человеческий клент имеет дружетвенный интерфейс, при заменяет сокращения типа "e e e n p s d" на "east east east north pickup south drop". При проигрывании промежуточных состояний мира между разными состояниями мира вставляется задержка.

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

В программе интересно реализована комманда "autocollect": В классе World в методе action_autocollect(), создаётся сервер-заглушка привязанный собственно к этому экземпляру мира и робот, привязанный к этому серверу. Робот умеет прокладывать путь через лабиринт, и вот этот робот и используется для хождения по лабиринту

Будем добавлять новые фичи, ну там монстров, NPC, прокачку персонажа?

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

Во-первых, мне 27 лет, и намёки на юношеское-там-что-то идут в сад вместе со своим отправителем.

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

В третьих, не нужно мне приписывать, что я там вынес и т.д. Лучше занимайтесь программированием.

И в четвёртых, про "не боитесь и т.д.": не боюсь. Мне Вашего кода боятся нечего :) Вы из тех людей, что любят всех учить и теоретизировать, как нужно делать, а как до дела доходит... начинаются гнилые отмазки, мол, это жизнь, заказчики, небо голубое, и т.д. Ведите себя по-мужски, умейте проигрывать молча.

Теперь я расскажу, что я вынес из всего этого. Лисп мне как раз интересен, но Ваше исполнение действительно сосёт (перейду на Ваши термины), и несколько раздражает, когджа Вы ещё после этого учите меня программировать и открываете тайны жизни. Вот некий ананимус классно портировал adv_server.py, мне очень понравилось, сразу видна красота лиспа.

P.S. Далее буду только читать (может быть), поскольку уже не интересно стало.

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

> Порешим на том что победила дружба :-) И лисперы прекратят вопли про быдлоязыки, по типу этого:

> Ибо воистину. Первый Язык, жемчужина посреди простых камней...

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

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

Ну то, что OCaml будет выполнять быстрее, это понятно, а вот за то, что
бы показать, что он самый краткий я и не стал бы бороться. Все таки
нет там синтаксического сахара python'а и lisp'а, да и стандартная
библиотека мягко говоря меньше.

to realsmart:
Что-то ты слишком вскипел. Если бы ты был внимателен, то заметил бы, что
вначале eugine_kosenko также относился к lisp скептически, но в отличие
от других попробовал и сделал выводы (свои, а не насаждаемые ему из
вне). Более того свои выводы он тебе не насаждает и не проповедует - он
их просто высказал. И разговаривает вполне в спокойной манере. Я не
понимаю, что ты так вскипел? В посте от 27.10.2006 1:14:47 единственное,
что могло вам не понравится, так это высказывание про юношеское
самоутверждение, так я его могу отнести также и на свой счет, но
почему-то я спокоен. Будьте спокойней и вы, я думал, что как раз сейчас
сложилась вполне дружественная атмосфера, а вы ее зачем-то нарушаете...

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

satanic-mechanic
()
Ответ на: комментарий от satanic-mechanic

realsmart, вы не подумайте, я действительно не имею против вас ничего...
Но перечитайте топик, там было что-то вроде от eugine_kosenko: "лисперы
пока молчат, поэтому я вот тут попробовал себя в лиспе и получилось так".
А лисперы действительно почему-то молчат. И разговор перешел вполне в
цивилизованное русло, давайте его также и продолжим. А по поводу
фанатизма, когда-то слышал примерно следующее: "на любую хорошую идею
всегда найдется неприятность в виде слишком ярых последователей".

P.S. Лисп действительно очень хороший язык. Просто разговоры про
улучшение на порядки - это чистый фанатизм. Современные языки (python,
ruby) очень сильно приблизились к нему по возможностям (я не спорю, что
достигнуть лиспа им не удастся (хотя бы в метапрограммировании из-за
лиспового синтаксиса)), поэтому лисп не дает такого преимущества, как
давал когда-то по сравнению с фортраном и C.

satanic-mechanic
()
Ответ на: комментарий от redvasily

>Порешим на том что победила дружба :-) И лисперы прекратят вопли >про быдлоязыки, по типу этого:

Что с чувством юмора ?

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

>И несмотря на всю свою идеальность и универсальность всё равно >сливают более специализированным и прагматичным "быдлоязыкам", как >только дело доходит до реальных проектов.

Вот уж вывод на пустом месте.

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

>Т.е. преимущества лиспа проявляются только на крупных проектах, которых не существует :-)

Нет, ну тут были какие-то ссылки. И я приводил ссылку на проект Prism. Вот как раз есть у них статейка по поводу применения Common Lisp в системе. Приведены свои аргументы по поводу, почему именно CL. Четыре странички, кажется. Можно ознакомиться здесь:

http://www.washington.edu/medicine/depts/radonc/research/computing/downloads/...

А крупные проекты были. В период, когда продавались дорогие LISP-машины, их было навалом. Но только это у тех, кто эти машины покупал. Т. е. внутри больших компаний и организаций. Надежды увидеть это все на столах в виде редактора Paint или MS Word (гы-гы) нет (пока).

Zubok ★★★★★
()
Ответ на: комментарий от satanic-mechanic

>А лисперы действительно почему-то молчат.

Некогда нормально поучаствовать. Тут вот кто-то два дня смог потратить на решение задачи, у меня и 2-х часов лишних нет :-((

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

> Вот уж вывод на пустом месте.

Не на пустом месте, а на собственном опыте. :) И я считаю, что:

1. S-выражения труднее читать и понимать, чем код на том же Питоне. Во всяком случае, подавляющему большинству людей. :)

2. До сих пор нет нормальных свободных реализаций Лиспа, пригодных для моих задач.

На предыдущей работе я возился с числодробильным софтом на фортране и C++. Пытался использовать Lush, но оказалось, что он не даёт особенных преимуществ. То есть, те куски кода, где нужна производительность, приходится переписывать в стиле C. Или просто переписывать на чистом C. В конце концов, оказалось, что проще все узкие места писать на С(++) или быдлофортране, а остальное делать на Питоне. Сейчас я занимаюсь гуями на (Py)Qt, и здесь Лисп отпадает хотя бы по той причине, что нет лисповских привязок для Qt. :) А для метапрограммирования в этих задачах и Питоновских замыканий и метаклассов хватает с лихвой. Ещё возился одно время с обработкой текстов. Довольно естественным казалось писать всё это на Лиспе, потом с Лиспа я плавно перешёл на OCaml, потому что его статическая типизация в таких задачах рулит. А с него - на Питон, правда, не по доброй воле, а потому, что начальство приказало. :) Особого выигрыша по сравнению с Камлом Питон не дал, но по крайней мере, для него больше библиотек и больше программистов. :) (Как побочный проект тогда появился http://pybtex.sourceforge.net/).

Хотя, если вы приведёте мне пример реального проекта, где Лисп объективно заруливает всех остальных, буду благодарен. :)

ero-sennin ★★
()
Ответ на: комментарий от eugine_kosenko

> Если это соглашение по именам констант, то почему command-reversion сделано без них?

Забыл :(

> И я еще видел переменные, окаймленные астериксами -- *blah* -- что это значит? И вообще, есть ли соглашения по кодированию и стилю программ на Лиспе и где об этом можно почитать?

Звёздочками принято окаймлять глобальные переменные. Читать можно http://www.norvig.com/luv-slides.ps и есть ещё http://www.lisp.org/table/style.htm

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

Можно, но необязательно :) Т.е. он там просто лишний

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

CLtL явно говорит, что нужно - form или forms :)

> Про (if (null x) () ...) -- хотел показать, что основой рекурсии является пустой список.

Лучше уж комментарии писать (хотя по мере того, как код становится всё проще и легче читать - очень трудно заставить себя это делать)

> Просто не знал :-). Получается, что для атомарных имен setf ничем не отличается от setq, но позволяет писать несколько присваиваний? Почему такой возможности нет у setq?

Есть и у setq. А setf для атомарных имён именно setq и использует (как правило - зависит от реализации, но результат в любом случае тот-же). Посему просто срабатывает привычка setq не использовать :)

P.S. А по малеёшим подозрениям лучше лезть в CLtL/HyperSpec :)

> Что делает #.? Насколько я знаю, хэш означает блокировку, для чего она в этом случае?

Ну, ты уже всё нашёл :) Да, read-time evaluation. Т.е. форма за #. вычесляется именно сразу после прочтения. Это позволяет в макру передать именно список, а не имя перемнной, его содержащей. Но нам это позволяет ещё сделать то, что defconstant выполняется в момент компиляции. С обычной переменной так не получится, если только не засунуть код в (eval-when...)

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

> SBCL уважаю, но под винду он еще малость сыроват, может к концу года похорошеет.

Именно сейчас за него взялись. Может мои надежды оправдаются (а ожидания - нет), и к v.1.0 и виндовая версия будет более мение ничего...

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

> Народ может кто шуканет сюда народ из fido7.ru.lisp? А то больно интересно читать, только примеров маловато.

На весь топик? Не, не надо :)

yyk ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.