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
()
Ответ на: комментарий от anonymous

Цитирую себя: «Вопрос идеологии в которой начинают с функции дело вкуса разработчиков»

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

Знатный слив с твоей стороны.

vertexua ★★★★★
() автор топика
Ответ на: комментарий от 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

Иерархия в которой ничего не понятно.

vertexua ★★★★★
() автор топика
Ответ на: комментарий от 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 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.