LINUX.ORG.RU

Решил попробовать написать некоторую вариацию restarts

 , ,


1

7

Для Ъ: перезапуски Lisp по-простому - более общая концепция exceptions, при которой стек не раскручивается, то-есть обработка исключительной ситуации происходит в месте возникновения, а не выше по стеку полностью прервав исполнение. То-есть концептуально алгоритм все еще может продолжить работу если код который его вызывал предложил способы разрулить нестандартные ситуации по мере выполнения. Отличие от лямбд переданных во внутрь алгоритма заключается просто в том, что они явно не передаются, а задаются в форме похожей на обычный exception и работают через 100500 уровней.

  object RestartContext{
    private val contextHolder = new ThreadLocal[PartialFunction[Any,Any]]{
      override def initialValue() = Map()
    }

    def context = contextHolder.get

    def context_=(value:PartialFunction[Any,Any]){
      contextHolder.set(value)
    }
  }

  class CatchHolder[T](body: =>T){
    def catchRestarts(catchBody: PartialFunction[Any,Any]):T={
      val oldContext = RestartContext.context
      RestartContext.context = catchBody.orElse(oldContext)
      try{
        body
      } finally {
        RestartContext.context = oldContext
      }
    }
  }

  def tryRestarts[T](body: =>T) = new CatchHolder[T](body)

  case class NotFoundRestartException() extends RuntimeException
  
  def raiseRestart[T](restart:T):Any={
    RestartContext.context.lift(restart) match {
      case Some(result)=>result
      case None => throw NotFoundRestartException()
    }
  }

Используем

  case class WhatIsNext(value:Int)

  abstract sealed trait CuriousRestart
  case class NextValue(next:Int) extends CuriousRestart
  case object HaveNoIdea extends CuriousRestart  

  def printNext(value:Int){
    // Cannot decide itself, this function is retarded
    raiseRestart(WhatIsNext(value)) match {
      case NextValue(next) => println("Next for %s is %s".format(value,next))
      case HaveNoIdea => throw new IllegalArgumentException("Unable to find next for %s".format(value))
    }
  }
  
  def main(argv:Array[String]){

    tryRestarts{
      printNext(10)
      printNext(20)
    }catchRestarts{
      case WhatIsNext(value) if (value<15) => NextValue(value+1)
      case WhatIsNext(_) => HaveNoIdea
    }
  }

Кейс классы необязательны, просто хотел выразить суть

Есть ряд моментов которые выглядят уныло. Испытываю физическую боль от вида [Any,Any], но что тут можно придумать? Ну и ThreadLocal - вынужденное зло. Может кто-то посоветуют как сделать без угрызений совести?

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

В отличии от лиспа тут не предусмотрен ручной выбор функции, все в коде.

P.S. Кастую еще имплементации рестартов (возможно ваши) на других ЯП в которых их изначально нету.



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

А мне, наоборот, внешний вид кода на лиспе нравится. Симпатично так, все красиво завернуто в скобочки. Еще красивые отступы. Моя твоя не понимай.

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

дал знак IDE чтобы отобразить методы, которые могут быть применены к объекту.

M-x slime-who-specializes Show all known methods specialized on a class.

RTFM!

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

RTFM!

Бесполезно. У него мозги уже закостенели. Он решил изучить Лисп и сделать выводы, а в итоге написал какой-то детский лепет про автодополнение, ООП и синтаксис.

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

Лисп почти непригоден потому что в нем функции, а не методы объекта.

Есть такое (достаточно обоснованное) мнение, что это - одна из существенных причин годности лиспа в целом и CLOS в частности.

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

Писать точку после имени переменной - это дело привычки. Есть и другие способы организации code completion'а.

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

Типов нет, я присваиваю результат переменной типа А, который вовращает метод класса В. Именно такие методы нужно показать. Динамическая типизация, этим все сказано.

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

Писать точку после имени переменной - это дело привычки

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

Есть и другие способы организации code completion'а.

Какие, кроме ручного вызова функций или текстового completion?

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

Какие, кроме ручного вызова функций или текстового completion?

У тебя проблемы с памятью? Первую страницу перечитай.

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

Мне только сказали что работает. Не сказали по какому принципу. Могу допустить что или рученьками команды набивать по тупому как все в SLIME или текстовое

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

По имени пакета, дубинушка.

рученьками команды набивать по тупому как все в SLIME

Идиот, в SLIME это и работает.

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

По имени пакета, дубинушка.

Facepalm.lisp. Выпей таблеток, сильно неудовлетворенный ты жизнью видно. Лисп никому не нужен? Это тяжело пережить, да...

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

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

(defclass B () ())

(defgeneric A (arg)
  (:method ((arg B))
    (declare (ignore arg))
    (format t "Hello world!")))

(defparameter *var*
  #'(lambda (x)
      (A x)))

Так?

Динамическая типизация, этим все сказано.

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

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

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

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

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

Facepalm.lisp

А что не так? Как еще назвать человека, который второй день не может понять такую простую фигню? И судя по всему, до сих пор не понял.

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

Засчитываем слив тогда?

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

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

Ну прочитал man, и что? Какая связь с предметом разговора?

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

Какой слив?

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

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

Ничего мне не отвечают. Ты блеешь о том что все уже написали на первой странице, а там кроме УМВР ничего нет. ados привел кусок кода без связи с темой разговора о completion и думает что ответил.

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

Придурок, последнее сообщение той ветки было мое с примером про client:send-string. Если ты не понял или был не согласен, надо было отвечать.

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

man declare?

Стандарт же не обязывает declare вообще что-то делать. Максимум можно надеяться на оптимизации в паре-тройке реализаций и на примитивный тайпчек в SBCL. Настоящей статической проверки типов это не даёт.

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

Вот грамотный человек подтянулся. Как вы относитесь к самой культуре превозношения динамической типизации?

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

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

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

Можно обойтись без точки. Как я понял, в лиспе просто сделано по другому. Название класса или его часть можно вынести в название функции (или метода - одна суть, все равно на низком уровне будет функция). Начинаешь в LispWorks набирать это название класса, нажимаешь Tab и сразу получаешь нужное тебе авто-дополнение. Другая идеология. Ты же пытаешься со своим уставом зайти в чужой монастырь. Что ты так пристал к этой точке?

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

Как вы относитесь к самой культуре превозношения динамической типизации?

Динамическая типизация это искусство писать частичные функции. К последним я в последнее время отношусь плохо. Например

;; (: foo (t t t -> t))
;; ^ наглая ложь если считать foo тотальной
(define (foo a b c) (+ a b c))

явно частична.

Статические системы типов с динамикой поверх (= top type) в этом смысле лучше. С другой стороны, там тоже есть частичность - именно поэтому существуют механизмы исключений и рестартов. Вопрос в том насколько мы готовы полагаться на эти механизмы - чем больше в языке тотальности, тем меньше. Вот лично мне нужны хотя бы примитивные статические проверки покрытия, теперь, когда я к этому привык, использовать динамику как-то уныло (например, по личным ощущениям - node.js самый ужасный язык / VM что я видел, отлаживать вообще непонятно как).

А касательно автодополнения - _даже_ если представить, что IDE будет знать тип лексического var, в выражении (dot var тут можно дополнять) всё не так просто, потому что это предполагает single-dispath, а он не single. То есть операция dot вообще не универсальна, может быть (method var1 var2 var3) - IDE должна смотреть в типы-классы (и это уже не compile-time, а рассматривание образа с помощью средств интроспекции вроде MOP - потому что динамика, метацикличность и горячее обновление) не только var1, но и var2 с var3, и на их «пересечении» искать метод. В хаскеле / ерланге / clojure автодополнения в стиле single-dispath тоже не практикуются - просто ментальность другая, при написании кода пляшут от функций а не от данных (в хаскеле ещё пляшут от данных в случае eDSL / data driven написания, но это несколько иное и параллельный процесс), емнип, Армстронг и Степанов высказывались на тему важности функций при проектировании (важности функторов, если угодно).

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

Точка вторична, типизация первична

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

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

А мне, вот, типизация перестала нравится. Я сужу по Scala. Написал, наверное, больше мегабайта кода на Scala. Все неплохо пока ограничиваюсь своим кодом, но когда я смотрю исходники библиотеки run-time, то от некоторых мест начинает тошнить. В непоследнюю очередь это связано с вывертами в типизации, особенно когда начинают мудрить с наследованием и типизацией в коллекциях, но в парсер-комбинаторах тоже не все идеально. Уж лучше бы было побольше ограничений как в C# или Java, чем вот так вот. Еще некоторые кадры с fprog.ru добавляют масла в огонь в моем предубеждении против статической типизации. Но колюсь, плююсь и продолжаю писать на Scala.

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

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

Абсолютно согласен. Без top-type иногда не обойтись. Мой код в теме - хороший пример. Да, я не хочу видеть много Any в своем коде, но похоже не обойтись в данном случае. Зачем тогда везде делать динамику?

Вопрос идеологии в которой начинают с функции дело вкуса разработчиков. dot-completion дествительно рассчитан на single dispatch, но можно dot-completion ограничить для первого параметра, не надо ограничивать весь ЯП. Естественно не в лиспе, у них многие фичи завязаны на s-notation и точку впилить туда будет странно.

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

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

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

Уйди, умные дяди общаются. Поругайся с мальчишками во дворе.

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

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

Не зная, что такое классы типов (type classes), в библиотеке коллекций Scala трудно разобраться. Они там во многих местах подразумеваются через implicits. Точнее, implicits выступают как средство реализации в Scala концепции классов типов. перемудрили, короче.

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

Не зная, что такое классы типов (type classes), в библиотеке коллекций Scala трудно разобраться.

А чем type classes от интерфейсов отличаются то? Судя по http://habrahabr.ru/post/73075/ те же интерфейсы, только с функциональной точки зрения. А что сложного в интерфейсах?

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

Не понял тебя. Я имел в виду, что даже Seq[+A].map имеет неявный параметр, который по сути очень близок к ограничению по классу типов.

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

Scala крутил немного, из воспоминаний про коллекции только то, что там было два набора: один с мутабельными, а другой с иммутабельными. А что там с ними не так?)

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

Или вот еще

trait Buffer[A] extends Seq[A] 
                   with GenericTraversableTemplate[A, Buffer]
                   with BufferLike[A, Buffer[A]] {
dave
()
Ответ на: комментарий от Norgat

А это, вообще, перл:

final class ListBuffer[A] 
      extends Buffer[A] 
         with GenericTraversableTemplate[A, ListBuffer]
         with BufferLike[A, ListBuffer[A]]
         with Builder[A, List[A]] 
         with SeqForwarder[A]
         with Serializable
dave
()
Ответ на: комментарий от dave

И этот map будет для произвольного Seq[A], верно? Но объявляется, не как метод Seq[A], а сам по себе? Я всё верно понял? Или таки этот map объявлен в классе Seq?

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

Там соль в том что он будет то для любого, я не уверен что в самом Seq, но он еще и в подклассах будет возвращать сам этот подкласс. Тоесть эффективно будет работать при произведении map над массивом, списком, итераторов, возвращая соответствующие объекты тех же классов.

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