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

Тоесть эффективно будет работать при произведении map над массивом

Да ладно, томозные коллекции в Scala, ни о какой эффективности и речи нет. С примитивами постоянный box/unbox идет, вся эта функциональщина тормозит изрядно.

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

Не, я не писал ничего о typeclasses. Относительно их Scala поддерживает как популярный subtype полиморфизм так и ad-hoc полиморфизм. В первом существует иерархия классов и правила совместимости типов плюс рантайм диспетчеризация. Во втором, по крайней мере в Scala «если есть специальный инстанс для класса А типа В, то разрешить вызывать этот метод на этапе компиляции для типа А, метод может также пользоваться B»

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

Нужно смотреть от ситуации до ситуации. Для number chrunching действительно иногда есть смысл применить java style. Но иммутабельность позволила мне ускорить систему из-за lock-free алгоритма по сравнению с классическими коллекциями. Еще есть специализация коллекций, пока подробно не исследовал

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

Как метод Seq[A], но результат зависит от передаваемого implicit, который автоматически подбирается компилятором исходя из контекста по определенным правилам. Эти implicits уже есть готовые и настроенные в самой библиотеке. Обычно map возвращает объект того же класса, т.е. такой же наследник Seq[A]. Но для некоторых типов A энтот implicit в теории может быть другим, а потому возвращаемый тип That может отличаться от текущего.

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

Welcome to Scala version 2.9.2 (Java HotSpot(TM) Server VM, Java 1.6.0_22).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.collection.immutable._
import scala.collection.immutable._

scala> val x = SortedSet(1, 5, 3, 2)
x: scala.collection.immutable.SortedSet[Int] = TreeSet(1, 2, 3, 5)

scala> case class Y(y: Int)
defined class Y

scala> x.map(y => Y(y))
res0: scala.collection.immutable.Set[Y] = Set(Y(1), Y(2), Y(3), Y(5))

В общем, проблема в том, что map - метод объекта, а не функция модуля. Авторы Scala сами создали трудности и сами же их успешно преодолели, переписав библиотеку коллекций к версии 2.8. Хотя не скрою, в Scala есть приятные вещи. После лиспа Scala - один из лучших языков на мой скромный взгляд.

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

Давай краткую выжимку, а то лень мне читать про тайпклассы простыни из той темки, т.к. хаскелем я не пользуюсь и не планирую)

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

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

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

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

Если проигнорировать другие преимущества скалы, то есть одно очень большое - она на JVM, потому мощь платформы и наличие технологий покруче лиспа будет. Но вот есть лисп на JVM - Clojure, и что? Променять Scala на Clojure я бы не стал.

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

Да, забавная штуковина. Хотя я всё равно в скалу не полезу (ну не переношу я жабовские либы (вернее извращённый java-ООП), а их так и так юзать, что печально). Лучше буду CL курить)

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

Ну, учитывая, что scalaz - это такая попытка дать нормальным людям возможность писать на скале не блюя каждые 2 минуты, я догадываюсь, что тебе не понравилось.

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

В обычном полиморфизме (subtype) у тебя есть класс Animal и подкласс Dog. Иерархия фиксирована, но ты вообщем хорошо знаешь как все работает, нечего объяснять. И Scala это поддерживает.

С тайпклассами на примере Scala у тебя есть просто класс Dog c методом «лаять». Ни от чего не наследуется. Есть тайпкласс например Animal и в нем методы «бежать» без имплементации. Есть понятие «инстанса тайпкласса». Например «инстанс Animal для класса Dog». Это уже реализация «бежать» для объекта Dog, который передали через параметр.

Допустим есть код, в который могут передать любой объект, который может быть животным и и нужно вызвать метод «бежать». В отличии от обычного полиморфизма где бы передали параметр Animal, тут передадут «T, такой для которого в области видимости существует instance Animal». Тоесть определили ограничение. И теперь это неизвестный T можно передать в инстанс и вызвать «бежать».

«Зачем эти геморы?», спросит внимательный читатель. Дело в том что нет иерархии. Можно в одном участке кода нагородить одних инстансов, а в другом других. А собака останется собакой с только ей присущими данными, без навязаной иерархии. Parent класс можно импортировать.

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

Ты опять. Я думал твои слова «не узнаешь» значили что ты наконец сделаешь вдоль.

Обоснуешь зачем делать библиотеку без документации и отсылкой «смотри код»? Многие класы не упрощают код

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

Давай краткую выжимку

Тайпклассы не нужно наследовать. Это не интерфейсы, а сигнатуры (была такая фишка в GNU C++).

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

Ты опять. Я думал твои слова «не узнаешь» значили что ты наконец сделаешь вдоль.

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

А вот первое сообщение в топике было мое. Ловко, да?

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

Если проигнорировать другие преимущества скалы, то есть одно очень большое - она на JVM, потому мощь платформы и наличие технологий покруче лиспа будет. Но вот есть лисп на JVM - Clojure, и что? Променять Scala на Clojure я бы не стал.

В моих глазах JVM скорее минус, чем плюс. Допустим, вознамерился я написать десктопное приложение. И что я вижу?

На винде и маках нужно включать в инсталятор JRE, который в запакованном виде занимает более 30 мегабайт. Представить только, тридцать мегабайт к загружаемому инсталятору! Да я разорюсь на хостинге.

Что имеем в лиспе? Hello-world для LispWorks занимает мегабайт восемь. В запакованном виде, а инсталятор пакуется, будет меньше в раза два-три. Здесь лисп лучше JVM.

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

Потому что те, для кого сделана библиотека, уже знакомы с концептами? Какая документация нужна для бифунктора, например, кроме исходного кода?

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

Вопрос идеологии в которой начинают с функции дело вкуса разработчиков.

Вот кстати - http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html

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

(defmacro dot (obj meth &rest args) `(,meth ,obj ,@args))

(dot obj meth ...) ;; IDE может видеть dot obj и предлагать нужные meth

(defmacro multi (&rest forms) `(,@(last forms) ,@(butlast forms)))

(multi obj1 obj2 ... meth) ;; аналогично - IDE должна производить поиск подходящих мультиметодов

ну то есть организовать постфикс, можно даже специальные скобки для этого добавить, чтобы не писать dot и multi. Естественно, это не реализуемо, потому что при наборе лиспокода не ясно какие типы будут у выражений (у obj* в данном случае) - это станет ясно только при выполнении (и может зависеть от времени суток). То есть автодополнение в стиле С++/Java это просто один из методов статического анализа кода который нельзя применить к динамике (не превращая её в статику).

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

Конкретно в скале, правда, наверняка и тайпклассы на костылях.

Это в хаскеле тайпклассы на костылях и сами суть костыли :) А в скале всё правильно делают с implicits.

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

Потому что лишняя сущность. Функции интерфейса можно складывать в обычные структуры:

data Functor f = Functor {
    _map :: forall a b. (a -> b) -> f a -> f b
}

data Monad f = Monad {
    _functor :: Functor f,
    _return :: forall a. a -> f a,
    _bind :: forall a b. f a -> (a -> f b) -> f b
}

listFunctor :: Functor []
listFunctor = Functor {
    _map = Data.List.map
}

listMonad :: Monad []
listMonad = Monad {
    _functor = listFunctor,
    _return = (:[]),
    _bind = (Control.Monad.>>=)
}

t = _map listFunctor (+ 1) $
    _bind listMonad [1, 2, 3] $
    \x -> _bind listMonad [4, 5, 6] $
    \y -> _return listMonad $ x * y

если добавить implicits / instances [1], то получится

map :: {- INSTANCE -} Functor f -> (a -> b) -> f a -> f b
map = _map

return :: {- INSTANCE -} Monad f -> a -> f a
return = _return

(>>=) :: {- INSTANCE -} Monad f -> f a -> (a -> f b) -> f b
(>>=) = _bind

t = map (+ 1) $
    [1, 2, 3] >>=
    \x -> [4, 5, 6] >>=
    \y -> return $ x * y

то есть то же самое что и с классами типов, только без введения сущностей constraints / typeclasses / multi-parametric, на базе обычных ADT и implicits/instances (которые в любом случае нужны и сами по себе довольно дешёвые фичи). При этом если ADT зависимы, то в них кроме функций интерфейса оказывается возможно положить ещё и утверждения о свойствах интерфейса которые должны доказываться в виде теорем в инстансах, например в Agda:

record Functor (F : Set → Set) : Set₁ where
  field
    map : ∀ {A B} → (A → B) → F A → F B

    .map-id : ∀ {A} → map{A} id ≡ id
    .map-comp : ∀ {A B C} {f : B → C} {g : A → B} → map (f ∘ g) ≡ map f ∘ map g

map : ∀ {A B F} ⦃ _ : Functor F ⦄ → (A → B) → F A → F B
map ⦃ f ⦄ = Functor.map f

чего классы типов совсем не умеют.

[1] https://lirias.kuleuven.be/bitstream/123456789/304985/1/icfp001-Devriese.pdf

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

record это модуль вокруг 1-конструкторского индуктивного типа данных, в field перечисляются аккессоры, то есть ортогональные функции интерфейса, дальше в модуле record можно писать производные от ортогональных функции с реализацией, любые другие определения. Так как это модуль - есть возможность локального импорта, сокрытия в private и т.п. Всё это можно явно расписать как module + data + функции.

Интересно, что Functor не помещается в Set, то есть является не множеством/типом, а... классом :) (в терминологии теории множеств).

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

Я согласен насчёт удобства точки, ибо оно легко доказуемо с цифрами в руках. Я пока что сделал для себя так:

(defstruct mystruct a b c)

(let-with-conc-type foo mystruct (make-my-struct)
  (+ foo^A foo^B foo^C))
С completion это не интегрировано, но хотя бы можно писать так, а не
(+ (mystruct-a foo) (mystruct-b foo) (mystruct-c foo))
Всё таки, чаще приходится читать код, чем писать. На это лисперы стандартно (не подумав) говорят, что есть :conc-name и :accessor. Я всё это пробовал, оба оба варианта порождают конфликты именования и/или ведут к потере производительности. Это тоже доказуемо, доказательство предоставляется читателю. В итоге оба варианта оказываются хуже точки. Под капотом у этой записи довольно много всего, и вот мой проект на эту тему. http://code.google.com/p/def-symbol-readmacro

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

без введения сущностей constraints / typeclasses / multi-parametric

А также без необходимости введения fun. deps., flexible instanses / contexts и проблем undecidable / overlapping / incoherent инстансов.

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

честно не могу понять зачем фанаты динамических языков так страдают

Заметь, у тебя претензии в основном не к лиспу конкретно, а к динамической типизации в общем, в python «автодополнение по точке» тоже не тривиальная для реализации задача, ее как-то понемногу осиливают в том же eclipse, но с весьма переменным успехом. В лиспе просто другое ооп, не такое как обычно, методы не принадлежат классам, а специализируются на них. Да, простой доступ к вложенным объектам через точку (именно к вложенным объектам, не к методам, которые можно применить к данному объекту) имхо полезная и юзабельная фича, но по какой-то причине эта практика не является общепринятой в мире лиспе, с другой стороны - никто не мешает тебе написать соответствующий макрос и пользоваться им в своих проектах. Да, дополнительный «осовремененный» набор макросов не помешал бы в стандартной либе и хороших доках его популяризирующих, но как и в любом другом случае должна быть критическая масса заинтересованных в этом адептов нового поколения с других взглядом на ортодоксальный лисп. Но их особо не видать. Что касается претензий к читабельности s-выражений - это на вкус и цвет, мне вот их читать вполне удобно. Как указал anonymous выше по треду, лисп - это, наверное, даже на сегодняшнй момент, один из самых удобных языков для создания «грязных» прототипов для экспериментов с eDSL, а проще - средство для создания _новых_ языков. Ждем еще N2, че они там покажут, но пока что гложут сомнения: для запила статически типизированного фреймворка для создания новых яп необходим слишком крутой и фундаментальный замес, до которого пока что не доперли даже в хаскеле (а сообщество там огого, хоть и цели немного другие, сколько проблем еще не решено) и радикально новый point-of-view + ресурсы (бабло и время) на исследовательскую группу по разработке и обкатке всего этого хотя бы на факториалах, вебне и gui. Такие дела.

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

Название класса или его часть можно вынести в название функции

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

Начинаешь в LispWorks набирать это название класса, нажимаешь Tab и сразу получаешь нужное тебе авто-дополнение

Авто-дополнение чего, названия класса? Так, наверняка, умеет каждый встречный-поперечный нотепад-- и прочие подобные поделия

Другая идеология

Никакой другой идеологии тут нет, обычный динамически типизированный язык с гомоиконностью и «немного» другим ооп из коробки

Ты же пытаешься со своим уставом зайти в чужой монастырь

Ортодоксы атакуют? :D

Что ты так пристал к этой точке?

Удобно же! Но судя по твоим предложениям писать без ide, ты - либо теоретик, либо олдскул-ваннаби с соответствующей производительностью труда

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

Это прием из 80-х, так в сишечке принято

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

Авто-дополнение чего, названия класса? Так, наверняка, умеет каждый встречный-поперечный нотепад-- и прочие подобные поделия

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

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

с соответствующей производительностью труда

А ну все ясно. Чего спорить с дебилом, у которого производительность труда измеряется размером сорцев?

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

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

Да нет, так принято в нормальных языках

В каких это, нормальных? Отсутствие дублирования назначения / специализации функции обеспечивается спецификацией ее предназначения через инкапсуляцию в именованном пространстве, другой вопрос, что в подавляющем большинстве классы и объекты создают новое пространство. Хотя хватило бы просто грамотной модульности и от ооп требовалась бы только симуляция генетической и поведенческой наследственности (то самое «обычное» ооп из плюсов и жабки) + контейнеры (классы объектов и сами объекты)

в которых удобство чтения считается важнее, чем удобство записи

Удобство чтения будет одинаковым, что namespace::method - это просто название функции, что namespace - отдельное самодостаточное пространство, но логичнее - если это все-таки пространство. Программирование - это гуманитарная дисциплина и логика поэтому здесь очень важна. А еще необходимо «чувство вкуса», стилистическое чутье. Вот почему языки с удобным и красивым (именно так) синтаксисом становятся популярными, а ветхое низкоуровневое невыразительное уг умирает под их натиском или остается в узких низкоуровневых домейнах

Так а разве надо что-то еще?

Хорошая модульность, а не ее симуляция

Подавляющую часть юзкейсов автомокмплита это покрывает

Если мы говорим о распространенных языках - то нет

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

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

Если ты, конечно, не жабамакака, которой платят за строчки - тут, конечно, без иде никуда.

В лиспе без ide тоже никуда, без slime - лисп неюзабелен *вообще*, так же как и python без соответствующих инструментов. Современная методология разработки подразумевает неотделимость среды (ide) и языка. Smalltalk задал этот тон и предопределил будущее

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

Правда жизни такова, что в случае с ЯП часто лишняя сущность позволяет очертить границы концепта. Часто есть фича ЯП или как альтернатива прием в этом ЯП. Но тогда этот прием имеет расплывчатые границы и приходится догадываться и расшифовывать что имел ввиду автор в том или ином случае.

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

>> соответствующей производительностью труда
> А ну все ясно. Чего спорить с дебилом, у которого производительность труда измеряется размером сорцев?

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

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

Ты упустил временной фактор... марксист? :D

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

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

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

Вот почему языки с удобным и красивым (именно так) синтаксисом становятся популярными

Практика как раз доказывает обратное - наиболее популярны языки с вырвиглазным алголоподобным синтаксисом.

Хорошая модульность, а не ее симуляция

В каком месте модульность связана с автокомплитом?

Если мы говорим о распространенных языках - то нет

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

Это только, если ты хреново знаешь язык на котором пишешь или тугодум.

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

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

При чем тут разработка на листочке?

Современная методология разработки подразумевает неотделимость среды (ide) и языка.

Нет, ничуть.

В лиспе без ide тоже никуда

При чем тут ИДЕ? Инкрементальная разработка лиспа - это свойство языка, абсолютно никак не связанное с ИДЕ.

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

Сколько будет сокрушающихся лисперов что образ выражения в памяти теперь сильно отличается от вида в коде?

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

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

Дурашка, ты же сам выше ратовал за то, что не стоит явно писать то, что и так ясно из контекста.

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

Практика как раз доказывает обратное - наиболее популярны языки с вырвиглазным алголоподобным синтаксисом.

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

В каком месте модульность связана с автокомплитом?

Если с модульностью беда, то да - автокомплитить тупо нечего :D А если она присутствует - то автокомплит как быстрая интроспекция объекта-модуля

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

Еще раз медленно и печально, тот же лисп без ide (emacs + slime) неюзабелен

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

И что, получается не так мало: 40-200 строк в человекодень

При чем тут разработка на листочке?

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

При чем тут ИДЕ? Инкрементальная разработка лиспа - это свойство языка, абсолютно никак не связанное с ИДЕ.

Поразрабатывай инкриментально на лиспе в блокноте, об успехах доложи

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

Дурашка, ты же сам выше ратовал за то, что не стоит явно писать то, что и так ясно из контекста.

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

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

Сколько будет сокрушающихся лисперов что образ выражения в памяти теперь сильно отличается от вида в коде?

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

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

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

И хаскель не назовешь хоть сколько-нибудь популярным языком.

Если с модульностью беда, то да - автокомплитить тупо нечего :D А если она присутствует - то автокомплит как быстрая интроспекция объекта-модуля

Я повторю вопрос - какая связь между модульностью и автокомплитом?

Еще раз медленно и печально, тот же лисп без ide (emacs + slime) неюзабелен

емакс + слайм это не иде. Это банальный блокнот который умеет гонять в/из лиспового рантайма данные. И ВСЕ. Нету там никакой иде.

И что, получается не так мало: 40-200 строк в человекодень

Ну а время, которое требуется затратить на печать 40-200 строк при условии отсутствия даже базового автокомплита, копипаста, сниппетов, да и вообще любой помощи со стороны иде вплоть до форматирования кода, не превышает 10 минут. Значит десять минут (на деле меньше, т.к. все вышесказанное на деле есть) в день вы пишите код, остальное время - собственно, занимаетесь программированием (то есть думаете, какой код надо писать). Значит наличие вашей точки с автокомплитами сэкономит вам хорошо если минуту-две в день. Не вижу в этом какой-то необходимой killer feature.

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

А ты проектируешь его на листочке?

Поразрабатывай инкриментально на лиспе в блокноте, об успехах доложи

Запускаешь SBCL и пишешь. Инкрементально, да. Или консоль у нас нонче тоже иде будет?

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

О чем ты, дурашка? Какие факториалы? Какие сложенные функции? Ты бредишь?

anonymous
()

Сенсация! Срочно в номер! Лоровские вьеб-девелоперы-формошлёпщики вынесли икспертное решение: Лисп не нужен!

den74 так вообще делфятник позорный.

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

Некоторое время я пытался задавать те или иные вопросы о косяках стандарта на c.l.l., они обычно звучали довольно провокационно, но я старался всегда предлагать путь к решению, если только мог его выдумать. Мне говорили, что эти проблемы только в моей голове, ха-ха, хотя во всех случаях есть контпримеры, когда в других языках то же самое делается в 10 раз легче, а обходных путей мало кто предлагал. В итоге я сделал свои обходные пути для большинства наиболее болезненных узких мест (отсутствие точки, система пакетов, жутко ограниченные и уродливые ридмакросы, лишние скобки в let,flet, уродское приведение к верхнему регистру). У меня получился в чём-то немного другой язык, зато от него не тошнит. Недавно я ещё придумал, как обойти ограничение на congruent lambda list, но поскольку родовыми функциями пользуюсь мало и теперь научился делать так, чтобы было удобно разбивать код на множество мелких пакетов, в библиотеку это решение не включил. Некоторые вопросы я так и не смог решить. Например, если я напишу (declare (type mytype myvalue)), то myvalue уже не может быть nil-ом, в отличие от C,Java или Delphi. Т.е, нужно или писать тип (or mytype null) с неизвестными последствиями для оптимальности, либо делать null object для каждого типа. Оба решения - уродство. Это - большая проблема, если внедрять статическую типизацию (а я планирую ещё поменять синтаксис, чтобы было удобнее с ней работать). И что с этим делать - я не знаю. Ещё одна проблема, что в половине случаев нужно искать место ошибки в файле. Я сделал небольшие утилиты, к-рые упрощают процесс, но полного решения нет и,видимо, в случае CL его не может быть, т.к. благодаря пресловутой гомоиконности информация о расположении исходника легко теряется.

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

емакс + слайм это не иде. Это банальный блокнот который умеет гонять в/из >лиспового рантайма данные.

Ты не осведомлен, по-моему. SLIME даёт не только completion, а ещё: подсказку по параметрам, показывает определение, показывает справку по стандартным функциям, тыкает в место ошибки (в SBCL), также там есть inspect-ор, возможность подправить исходник и перекомпилировать одно определение или целый файл (та самая пресловутая инкрементная разработка), автоотступы. Каждая из этих фич, по отдельности и все они вместе - это существенный выигрыш в производительности труда (включая чтение кода, его написание, отладку и тестирование).

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

И хаскель не назовешь хоть сколько-нибудь популярным языком

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

Я повторю вопрос - какая связь между модульностью и автокомплитом?

Это припадок уже начался или что? Я не нанимался репетитором для умственно отсталых. Киворд инстроспекция модуля ты фильтранул из своего поля внимания?

емакс + слайм это не иде

А ты знатный звездочет :D den73 ниже отписал тебе, дубинушка

Ну а время, которое требуется затратить на печать 40-200 строк при условии отсутствия даже базового автокомплита, копипаста, сниппетов, да и вообще любой помощи со стороны иде вплоть до форматирования кода, не превышает 10 минут

Хватит бредить, во время написания кода происходит и его постоянная модификация, рефакторинг, занимает процентов 20-30%, с предложенными тобой каменным топором и святым духом - все 99%

А ты проектируешь его на листочке?

Проект - да, листочком выступает и обычный листочек и система документооборота с системой контроля версий, набор схематических набросок вручную и с помощью специализированных средств

Запускаешь SBCL и пишешь. Инкрементально, да. Или консоль у нас нонче тоже иде будет?

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

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

часто лишняя сущность

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

Вот ещё на тему функциональных зависимостей:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances
           , IncoherentInstances #-}

-- -----------------------------------------------------------------------------
-- * 1-parametric typeclass.

class Index t where
  index :: t -> Integer

instance Index Integer where
  index = id

testInteger = index (5 :: Integer)
-- :: Integer
-- => 5

-- {- second -} instance Index Integer where
--   index = (+ 1)
-- 
-- ^ no way.

instance Index [t] where
  index = toInteger . length

testList1 = index [1, 2, 3]
-- :: Integer
-- => 3

instance Index [Integer] where
  index = (+ 1) . toInteger . length

testList2 = index [1 :: Integer, 2, 3]
-- :: Integer
-- => 4

-- -----------------------------------------------------------------------------
-- * 3-parametric typeclass with two fun. dep's.

class Pair p a b | p -> a, p -> b where
  first :: p -> a
  second :: p -> b
  pair :: a -> b -> p
  -- no propositions.

instance Pair (x, y) x y where
  first = fst
  second = snd
  pair = (,)
  -- no proofs.

-- ** Bad instance against prop's.

instance Pair (Integer, Integer) Integer Integer where
  first = (+ 1) . fst
  second = snd
  pair = (,)

test1 = first (1 :: Integer, 2 :: Integer)
-- :: Integer
-- => 2

test2 = first ('c', 5)
-- :: Char
-- => 'c'

module FD where

open import Level
open import Function
open import Data.Nat hiding ( zero; _⊔_ )
open import Data.List
open import Data.Product
open import Relation.Binary.PropositionalEquality

-- -----------------------------------------------------------------------------
-- * 1-parametric multi-level record ("typetype", not "typeclass").

record Index {l} (T : Set l) : Set l where
  field index : T → ℕ

-- ** Ad-hoc polymorphic function.

index : ∀ {l} {T : Set l} ⦃ _ : Index T ⦄ → T → ℕ
index ⦃ i ⦄ = Index.index i

-- ** `ℕ' instances and tests.

ℕ-Index-1 : Index ℕ
ℕ-Index-1 = record { index = id }

test-ℕ-1 = index 5
-- : ℕ
-- ⇒ 5
-- using `ℕ-Index-1'

ℕ-Index-2 : Index ℕ
ℕ-Index-2 = record { index = λ x → x + 1 }

test-ℕ-2 = index ⦃ ℕ-Index-2 ⦄ 5
-- : ℕ
-- ⇒ 6
-- using `ℕ-Index-2'

yellow-test-ℕ = index 5
-- ^ Scope conflict between `ℕ-Index-1' and `ℕ-Index-2'.

-- ** Polymorphic / non-polymorphic `List' instances and tests.

List-Index-poly : ∀ {l} {T : Set l} → Index (List T)
List-Index-poly = record { index = length }

-- red-test-List-poly = index (1 ∷ 2 ∷ 3 ∷ [])
-- ^ `Index (List ℕ)' instance isn't presented.

test-List-poly = index ⦃ List-Index-poly ⦄ (1 ∷ 2 ∷ 3 ∷ [])
-- : ℕ
-- ⇒ 3
-- using `List-Index-poly'

List-Index : Index (List ℕ)
List-Index = record { index = (λ x → x + 1) ∘ length }

test-List = index (1 ∷ 2 ∷ 3 ∷ [])
-- : ℕ
-- ⇒ 4
-- using `List-Index'

-- -----------------------------------------------------------------------------
-- * 3-parametric multi-level record ("typetype" again).

record Pair {a b c} (T : Set a) (T₁ : Set b) (T₂ : Set c) : Set (a ⊔ b ⊔ c) where
  field
    first : T → T₁
    second : T → T₂
    pair : T₁ → T₂ → T

    -- propositions:
    .first-pair : ∀ {x y} → first (pair x y) ≡ x
    .second-pair : ∀ {x y} → second (pair x y) ≡ y

-- ** Ad-hoc polymorphic functions.

first : ∀ {a b c} {T : Set a} {T₁ : Set b} {T₂ : Set c} ⦃ _ : Pair T T₁ T₂ ⦄ → T → T₁
first ⦃ p ⦄ = Pair.first p

second : ∀ {a b c} {T : Set a} {T₁ : Set b} {T₂ : Set c} ⦃ _ : Pair T T₁ T₂ ⦄ → T → T₂
second ⦃ p ⦄ = Pair.second p

pair : ∀ {a b c} {T : Set a} {T₁ : Set b} {T₂ : Set c} ⦃ _ : Pair T T₁ T₂ ⦄ → T₁ → T₂ → T
pair ⦃ p ⦄ = Pair.pair p

-- ** `×' polymorphic instance.

×-is-Pair : ∀ {b c} {T₁ : Set b} {T₂ : Set c} → Pair (T₁ × T₂) T₁ T₂
×-is-Pair = record
  { first = proj₁
  ; second = proj₂
  ; pair = _,′_
  -- proofs:
  ; first-pair = refl
  ; second-pair = refl
  }

-- ** `×' non-polymorphic instance.

×-is-Pair-over-ℕ : Pair (ℕ × ℕ) ℕ ℕ
×-is-Pair-over-ℕ = ×-is-Pair
-- ^
--   ×-is-Pair { first = (λ x → x + 1) ∘ first ⦃ ×-is-Pair ⦄ }
-- 
-- isn't provable.

-- ** Valid tests.

test-1 = first ⦃ ×-is-Pair ⦄ (1 , 2)
-- : ℕ
-- ⇒ 1
-- using `×-is-Pair'

test-2 = first {zero} {zero} {zero} {ℕ × ℕ} {ℕ} {ℕ} (1 , 2)
-- : ℕ
-- ⇒ 1
-- using `×-is-Pair-over-ℕ'

test-3 : ℕ
test-3 = second (1 , 2)
-- : ℕ
-- ⇒ 2
-- using `×-is-Pair-over-ℕ'
quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.