LINUX.ORG.RU
ФорумTalks

Более лучший Лисп

 


3

9

Что бы вы изменили и каким образом в своем любимом/нелюбимом диалекте Лиспа, чтобы он стал ещё лучше? Расскажите обо всех своих грязных фантазиях.

Лиспосрач (и те два унылых анонимуса) не приветствуется.

Перемещено tazhate из development

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

Это как же упороться надо, чтобы ебланг в продакшене использовать?!? Они б еще на брейнфаке писали.

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

То есть в C++ баним

Я не призываю банить и вообще ни к чему не призываю. У меня чисто практическая проблема: как работать на лиспе более производительно и как привлечь сторонние силы к этому. Я вижу, что мне мешает синтаксис лиспа настолько же, насколько помогают его возможности как среды. Но я не вижу, как это решить в рамках лиспа, потому что я приложил к этому большие усилия (несколько месяцев труда, наверное, на протяжении большого интервала времени). И всё же в данную секунду я всё ещё занят решением проблемы: а как использовать в лиспе CamelCase? Хотя приступал к ней уже раза три. И пока не знаю, чем это сегодня закончится. Фраза «другой синтаксис» позволяет разрубить гордиев узел.

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

Полагаю, что вы и SpringSource считаете упоротой конторой?

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

У тебя лисп находится в несвойственной ему нише - прослойка между Delphi и 1c. Разрабов ты ищешь дешевеньких, на оклад java-middle, вероятно, без перспектив ни карьерного, ни профессионального роста. Постоянно хочешь CamelCase и прочих странностей. Расскажи, как ты вообще лисп решил использовать, зачем? Подсадил кто, жертва пропаганды? Легаси? Если все так плохо, почему его просто не выбросить из проекта и заменить на что-то другое?

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

несвойственной ему нише

А я не понял, ты за лисп или против? Если против, то отвечать на нападки нет смысла, если за - то ты сомневаешься в универсальности лиспа?

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

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

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

Если все так плохо, почему его просто не выбросить из проекта и заменить на что-то другое?

Во-первых, пока я работаю один, всё достаточно хорошо, т.к. код на лиспе пишется довольно быстро.

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

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

den73 ★★★★★
()

Предлагаю ещё одну радикальную идею

В соответствии с Google Style Guide переделать все функции под стандарт протокол:функция.

Будет что-то вроде

(function:new list:circular-p (object)
 "Returns true if OBJECT is a circular list, NIL otherwise."
 (and (list:? object)
      (do ((fast object (list:cddr fast))
           (slow (list:cons (list:first object) 
                            (list:next object)) (list:next slow)))
           (nil)
       (unless (and (cons:? fast) (list:? (list:next fast)))
            (return nil))
           (when (eq fast slow)
           (return bool:t)))))

В плюсе: не будет over 900 запрещённых к использованию имён.

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

Так кто тебе сейчас не даёт писать

(defun MyNiceFunction () ...)

Вроде как всё компилируется и работает (MyNiceFunction ...)

Или у тебя в коде уже есть, например, mynicefunction с совсем другим функционалом?

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

затем, что mynicefunction нифига не читабельно.

А (print 'defun) должно выдавать «defun»?

Здесь нет хорошего однозначного решения, но у меня выдаёт defun

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

вот так

'(defun Func |arg| |ARG|)

(defun Func |arg| arg) но не хотелось бы это обсуждать здесь, мы по-моему, уже зафлудили ветку.

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

Уверен, что (print 'CLOS) у тебя тоже выдаёт «clos».

P.S. К теме треда вроде относится. Вполне тянет на «грязную фантазию» по извращению над именами символов.

P.P.S. А продублировать все символы с downcase'ом не проще?

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

Это как же упороться надо, чтобы ебланг в продакшене использовать?!?

А что там нужно использовать? Дай угадаю - ЖАБУ?

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

P.P.S. А продублировать все символы с downcase'ом не проще?

тогда они будут не eq исходным и возможны самые разнообразные последствия...

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

https://github.com/edicl/hunchentoot

http://en.wikipedia.org/wiki/Reactor_pattern,

В смысле, hunchentoot — реализация Reactor pattern (или, по факту, скорее Proactor везде, гдн есть потоки)? И чем это плохо? Или в чём hunchentoot «на 10 лет» отстал от реализаций в других языках?

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

А я не понял, ты за лисп или против?

Что, хочешь быстренько поделить на свой-чужой? :) Я за здравый смысл.

ты сомневаешься в универсальности лиспа?

Конечно. Это «язык общего назначения», значит он уже не универсальный. Т.е. это точно не DSL. И кроме абстрактной «универсальности» существует конкретная такая Целесообразность инструмента для решения *конкретной* инженерной задачи (комплекса задач экономических).

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

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

Т.е. на 4К уе / мес не можешь найти лиспера? Неверю! (с)

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

hunchentoot — реализация Reactor pattern (или, по факту, скорее Proactor везде, гдн есть потоки)?

Наоборот, это _не_ реализация ни reactor, ни proactor, ни leader/follower, ни чего-то ещё подобного. Это классический multi-threaded сервер с блокирующим IO и с one thread per client моделью обработки соединений.

И чем это плохо? Или в чём hunchentoot «на 10 лет» отстал от реализаций в других языках?

В своей архитектуре и, как следствие, в latency.

На тему reactor на гитхабе находится http://github.com/sshirokov/hinge.

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

Что, хочешь быстренько поделить на свой-чужой?

Нет, хочу избежать дискуссии.

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

я провёл маркетинг, получилось 74 грязными средняя зарплата по вакансиям разработчиков, например, по 1С или по Дельфи.

Т.е. это точно не DSL

Delphi более DSL? Разве только благодаря культуре и сообществу, но не сам по себе.

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

к отсутствующей статической типизации

Не надо грязи, она не отсутствует, а просто неудобна.

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

костыль к отсутствующей статической типизации

Типизация как раз есть. Как явная через (declare ...), так и неявная через type inference:

(defun test (x) (+ (length x) x))
; in: DEFUN TEST
;     (+ (LENGTH CL-CAIRO2::X) CL-CAIRO2::X)
; 
; caught WARNING:
;   Derived type of X is
;     (VALUES SEQUENCE &OPTIONAL),
;   conflicting with its asserted type
;     NUMBER.

Костыль к тому, что сейчас я не могу назвать ни поле метода, ни функцию в модуле length, потому, что есть станадртный length, работающий на последоавтельностях. Не могу сделать функцию first на свой объект, потому как есть стандартная, работающая только на списках.

Google Style предлагает для всех новых типов/протоколов делать отдельные пакеты и не использовать в имени функции префикс (как сейчас list-length, symbolp, package-name, ...).

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

«SBCL-специфичная штука»

Вот её бы в стандарт внесли (вместе с tail-call optimization). А то в виде библиотеки нормальный type inference будет включать реализацию половины компилятора :-(

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

Вот её бы в стандарт внесли

Сначала нужно разрешить дихотомию встроенных типов с deftype и CLOS типов, тогда можно сделать generic first для класса list и вместо (list:first object) писать просто (first object) - для динамических объектов будет обычная динамическая диспетчеризация CLOS, а для символов с известным синтаксическим типом - статическая, то есть просто вызов функции.

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

Сначала нужно разрешить дихотомию встроенных типов с deftype

Не путай типы и классы. И имей в виду, что ещё есть alist:copy, list:copy, tree:copy и cons:copy. А класс у них один (также, как и внутреннее представление).

Альтернатива: https://github.com/fare/lisp-interface-library Но там предлагагается писать (pure:lookup <list> object) вместо (list:find object). По мне — сильно длинно.

И зачем это надо для инференса или TCO?

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

И все встроенные типы имеют CLOS-класс:

> (class-of '(1 2 3))
#<BUILT-IN-CLASS CONS>
> (class-of nil)
#<BUILT-IN-CLASS NULL>
monk ★★★★★
()
Ответ на: комментарий от den73

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

При опыте работы >3 лет она соответствует действительности. Киев, senior software инженегр, java - тынц. В мск-то по-минимуму больше на 20-30%, не?

Т.е. это точно не DSL

Delphi более DSL?

При чем тут Delphi? DSL это разные *hdl-и, *-sql, прочие языки математических cad-ов.

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

Не понял о чем ты, но можешь все-таки ответить на вопрос «почему лисп?», как ты к нему пришел и зачем все это продолжаешь, если *столько* боли вызывает весь процесс, от начала до конца? Подсадили фанбои обманули? :)

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

к отсутствующей статической типизации

Не надо грязи

o_0 *triple-facepalm*, откуда столько эмоций по поводу констатации технического факта?

она не отсутствует, а просто неудобна.

Т.е. в CL *есть* статическая типизация? (не опциональная, не частичная)

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

Google Style предлагает для всех новых типов/протоколов делать отдельные пакеты и не использовать в имени функции префикс

В принципе, разумно.

Типизация как раз есть. Как явная через (declare ...)

Это мы знаем, но дефолтная типизация динамическая.

так и неявная через type inference:

А это, скорее всего, зависимая от реализации «недокументированная» (не стандартизированная) возможность.

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

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

Боюсь спросить, а оно нужно? :)

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

Не путай типы и классы.

Любому CLOS классу соответствует точный тип, но не любому типу соответствует точный класс, точнее, при переходе от типов к классам информация стирается. Например:

* (type-of #(1 2 3))

(SIMPLE-VECTOR 3)
* (class-of #(1 2 3))

#<BUILT-IN-CLASS SIMPLE-VECTOR>
* (type-of "123")

(SIMPLE-ARRAY CHARACTER (3))
* (class-of "123")

#<BUILT-IN-CLASS SB-KERNEL::SIMPLE-CHARACTER-STRING>
* (type-of (make-array 3 :element-type 'fixnum :initial-contents '(1 2 3)))

(SIMPLE-ARRAY FIXNUM (3))
* (class-of (make-array 3 :element-type 'fixnum :initial-contents '(1 2 3)))

#<BUILT-IN-CLASS SB-KERNEL::SIMPLE-ARRAY-SIGNED-BYTE-61>

Соответственно, в методах нельзя провести диспетчеризацию по «вектор длиной 3», «массив именно fixnumов», «массив массивов или число» и т.п. типам. Простым (непараметрическим) типам можно сопоставить структуру-обвёртку и производить диспетчеризацию по ней, боксируя и разбоксируя значения туда-сюда.

И имей в виду, что ещё есть alist:copy, list:copy, tree:copy и cons:copy. А класс у них один (также, как и внутреннее представление).

Это должно быть

(defpackage #:foo)
(in-package #:foo)

(cl:defstruct null)
(cl:defstruct cons car cdr)
(cl:deftype list () '(cl:or null cons))
(cl:defstruct list@ (list cl:nil :type list))

(cl:defgeneric copy (object))

(cl:defmethod copy ((object list@))
  (cl:format cl:t "copy list ~S~%" object))

(cl:deftype tree () 'list)
(cl:defstruct tree@ (tree cl:nil :type tree))

(cl:defmethod copy ((object tree@))
  (cl:format cl:t "copy tree ~S~%" object))

(cl:let* ((list (make-list@ :list (make-cons :car 1 :cdr (make-null))))
          (tree (make-tree@ :tree (list@-list list))))
  (copy list)
  (copy tree))

defstruct/defclass это типы произведения, deftype/member - перечислимые типы, deftype/or - типы суммы, классов-обёрток list@ и tree@ быть не должно, диспетчеризация должна производится непосредственно по типам list и tree, deftype tree тут играет роль типажа (trait).

На Scala бы это так выглядело:

class Cons(carI: Any, cdrI: Any) { // ~ defstruct cons

  var car: Any = carI
  var cdr: Any = cdrI

  override def toString(): String = "(" + car + " . " + cdr + ")"

  def copy {
    println("copy cons %s".format(this))
  }

}

trait Tree extends Cons {

  override def copy {
    println("copy tree %s".format(this))
  }

}

object Test {

  val cons = new Cons(new Cons(1, 2), 3)
  val tree = new Cons(new Cons(1, 2), 3) with Tree

  def test {
    cons.copy
    tree.copy
  }

}

в духе обычного ООП, либо без методов copy в классах так:

trait Copyable[A] {
  def copy(a: A): A // ~ defgeneric
}

implicit object CopyableCons extends Copyable[Cons] {
  def copy(cons: Cons): Cons = ... // ~ defmethod for cons
}

trait Tree extends Cons {} // ~ deftype tree = cons

implicit object CopyableTree extends Copyable[Tree] {
  def copy(tree: Tree): Tree = ... // ~ defmethod for tree
}

ближе к лисповым defgeneric и defmethod вне классов.

Наконец, если в CL будут настоящие синтаксические типы и compile/runtime диспетчеризация в методах по классам и типам, то можно написать аналогично with в Scala с помощью declare:

(let* ((lst (list 1 2 3))
       (tr list))
  (declare (list lst)
           (tree tr))
  (copy list)  ;; copy for list
  (copy tree)) ;; copy for tree

или

(let* ((lst (list 1 2 3))    ;; list type infered
       (tr (the tree list))) ;; set tree type
  (copy list)  ;; copy for list
  (copy tree)) ;; copy for tree

И зачем это надо для инференса или TCO?

Для них - не зачем, хотя диспетчеризация по типам это просто «надо». Но вообще это на тему того что в гуглостилях предлагают статическую типизацию x : T реализовывать разбрасыванием разных x по разным пакетам символизирующих разные типы T.

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

Хотя тут есть два момента:

1) Динамическая диспетчеризация в методах по типам это больше боксирования. Пока язык в основе своей динамический это может быть слишком дорого.

2) Язык динамический, полностью статическим по умолчанию стать не сможет, поэтому (copy list) и (copy tree) это слишком зыбко (а если там забыт the и типо-тега не появилось? будет copy-list для tree). Поэтому предпочтительней писать copy-list/list:copy и copy-tree/tree:copy.

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

Боюсь спросить, а оно нужно?

Это как минимум оптимизация, странно, что SBCL её не делает.

Нельзя.

(defmethod test (any)
   1)

(defun test1 ()
  (test1 '(1 2 3))

(defmethod test ((list list))
   2)

Тогда при инлайнинге test1 всё равно вернёт 1, что неверно.

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

Ну именно так, вообще-то можно и в CL

(cl:in-package :cl2)
(cl:defclass cons ()
  ((car :accessor car :initarg :car)
   (cdr :accessor cdr :initarg :cdr)))

(cl:defclass list (cons) ())

(cl:defclass tree (list) ())

(cl:defclass acons (list) ())

(cl:defun cons (a b &optional (type 'cons)) (cl:make-instance type :car a :cdr b))

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