Scala
Читаю книжку Одерского, до основной шизы еще не добрался, но такое ощущение, что в скале чрезмерно много синтаксического сахара. Типа "тут вы можете скобки опустить, а тут вместо скобок использовать фигурные скобки, а тут мы прямо в параметрах класса сделаем их полями, а в multiline string literal вы можете сделать отступ и stripMargin" и прочая и прочая в том же духе.
Основное из этого, видимо - function literals и вызов методов в стиле a methodName b, без точек и скобок, что делает код более лаконичным, одновременно позволяя при желании превратить код в нечитабельный ад.
Заодно по наводке
jdevelop глянул на http://spray.io/ https://github.com/spray/spray/wiki
Примеры там, конечно, знатный abuse возможностей языка и вычислений на типах, типа extraction-директив с HList в качестве параметра типа.
Clojure по сравнению с этим выглядит более простой и логичной, хотя я не уверен, можно ли сравнивать совершенно разные языки, общего у которых только функциональщина и иммутабельность иногда.
PS: Вот, к примеру:
https://github.com/spray/spray/blob/master/docs/documentation/spray-routing/code/docs/HttpServiceExamplesSpec.scala
В SimpleService HttpResponse реализован как html-код написанный прямо внутри скала-кода.Сижу уже 30 минут ищу, где это преобразование реализовано и как. Т.е. не видя отдельных литералов и их типов (которые без загрузки всего оного кода с зависимостями в IDE/интерпретатор еще и не увидишь), с ходу догадаться, что происходит, достаточно сложно. XML literals, встроенные в язык и где-то implicit для конверсии.
PPS: implicit evidence:
http://jim-mcbeath.blogspot.com/2008/11/scala-type-infix-operators.html
http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
По-моему, это уже достаточно сложно, чтобы увлечь психов и стать новыми крестиками. Вот
xeno_by еще приделает макросы - и совсем хорошо станет.
Основное из этого, видимо - function literals и вызов методов в стиле a methodName b, без точек и скобок, что делает код более лаконичным, одновременно позволяя при желании превратить код в нечитабельный ад.
Заодно по наводке
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif)
Примеры там, конечно, знатный abuse возможностей языка и вычислений на типах, типа extraction-директив с HList в качестве параметра типа.
Clojure по сравнению с этим выглядит более простой и логичной, хотя я не уверен, можно ли сравнивать совершенно разные языки, общего у которых только функциональщина и иммутабельность иногда.
PS: Вот, к примеру:
https://github.com/spray/spray/blob/master/docs/documentation/spray-routing/code/docs/HttpServiceExamplesSpec.scala
В SimpleService HttpResponse реализован как html-код написанный прямо внутри скала-кода.
PPS: implicit evidence:
http://jim-mcbeath.blogspot.com/2008/11/scala-type-infix-operators.html
http://stackoverflow.com/questions/3427345/what-do-and-mean-in-scala-2-8-and-where-are-they-documented
По-моему, это уже достаточно сложно, чтобы увлечь психов и стать новыми крестиками. Вот
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif)
no subject
Такой if в любом языке пишется, достаточно будет обернуть аргументы в delay. С другой стороны, в хаскеле нельзя реализовать свой begin - он в хаскеле встроен (и называется case). То есть в хаскеле приходится руками оборачивать выражения в force. Это известная эквивалентность ленивого и энергичного порядка. На языке теорката она выражается в том, что в категории соответствующей ленивому порядку нету сумм, а в категории, соответствующей энергичному порядку - произведений, т.о. полученные категории дуальны.
no subject
В строгом языке - все аргументы, в ленивом - в нескольких местах.
no subject
no subject
no subject
В ленивом языке надо всегда ставить force вокруг первого аргумента кейза, В энергичном - delay вокруг веток if. Но поскольку и там и там это делает невыразимая в рамках языка спецформа (case и if соответственно)., то на практике ни там ни там никто вообще ничего не ставит. Важно, что ситуация совершенно зеркальна.
Тут следует только отметить, что force в ленивом ЯП выразить нельзя (если у нас уже не встроен кейз, который неявно вызывает force как в хаскеле), А вот delay выразить можно - это санка. Естественно, если мы говорим о классическом лямбда-исчислении, то там будет нарушена семантика (т.к. санка необходимо должна иметь переменную), так что указанная выше дуальность не нарушена. Но с точки зрения "человеческой" семантики функция без аргументов, которая моделирует delay в энергичном языке выглядит намного естественнее и лучше вписывается в исчисление, чем force, который вообще неясно как выражать, чистый хак.
no subject
fibs = 0:1:zipWith (+) fibs (tail fibs)
Я пишу всего две функции, которые будут считать строго голову и строго хвост и сделаю список чисел Фибоначчи полностью строгим.
http://thesz.livejournal.com/906786.html
fibsAsBottom = strictTail $ strictHead $ fibs
Сколько и чего вам нужно будет написать, чтобы сделать из бесконечного энергичного списка чисел Фибоначчи ленивый? Считайте, что все функции в первом определении выше энергичные, и сам список тоже.
no subject
Я не понял вопроса. Что из чего следует сделать? Известно, что "энергичные бесконечные списки" не существуют. Как из того, что не существует, можно сделать нечто существующее?
Сформулируйте четко и ясно, что вы хотели сказать, пользуясь общепринятой терминологией и не выдумывая своих понятий. Это необходимое условие, чтобы собеседник мог вас понимать.
Напоминаю, о чем мы говорили - на каждый if/case в энергичном/ленивом языке надо ставить delay/force, иначе ничего не будет работать. Т.о. места обязательных расстановок lazy/strict аннотаций строго совпадают. При чем эти аннотации расставляются автоматически, соответствующей спец-формой (if/case). В результате в коде никаких аннотаций нет. Ни в ленивом ни в энергичном случае. Это подтверждается экспериментально - мы спокойно пишем код безо всяких аннотаций. Потому в большинстве языков даже и возможности расставить аннотации руками нет - это просто никому не нужно.
Теперь, еще раз, что вы хотите доказать и как это соотносится с числами Фибоначчи?
no subject
no subject
> По моим соображениям, при энергичном порядке вычислений по умолчанию и ленивости в виде аннотаций, эти самые аннотации надо расставлять везде, где по дизайну программы могут проходить ленивые значения и их надо сохранить ленивыми. Это практически все библиотечные функции, по-моему. А также очень много мест в коде программы - еще раз подчеркну: везде, где по дизайну программы могут проходить ленивые значения и их надо сохранить ленивыми.
Как я понимаю вопрос лишь в том, что считать умолчанием, а что выставлять аннотациями. На мой взгляд все очевидно - аннотациями должна выставляться ленивость. Т.к., в самом деле, если для вычисления с точки зрения семантики без разницы, быть ленивым или энергичным, то его следует делать энергичным из соображений производительности. Поскольку к таким выражениям относятся 99% выражений во всей программе - если предположить иное, то получилось бы, что нам практически на каждое выражение надо ставить аннотацию строгости.
Ваш аргумент можно было бы принять, но вы подразумеваете тут полную бесконтрольность - то есть у нас-де ВНЕЗАПНО может куда-нибудь прийти санка, а раз может...
Но такой ситуации быть не должно, конечно же - все места, куда должно прийти ленивое вычисление, должны быть фиксированы заданием соответствующего типа. f: Promise Int -> Int - может прийти санка, f : Int -> Int - не может прийти санки. Делаем Promise монадой и обеспечиваем автоматический лифтинг ф-й в нее - в результате весь код будет выглядеть одинаково - и ленивый и энергичный, а нам лишь надо будет в граничных местах заворачивать или вытаскивать значение из lazy-монады где это явно надо.
То есть если лень неконтролируема (как в хаскеле) - автоматическая ленивость с опциональной энергичностью имеет смысл, но если есть контроль (как это должно быть) - смысла нет, автоматическая лень вредит и все усложняет.
no subject
Для меня важней производительность программиста. Поэтому для меня предпочтительней ленивый порядок вычислений, при котором выше модульность программы и её проще писать, ибо не надо задумываться, что же будет вычислено, а что нет.
no subject
В общем, описанное выше решение (фиксация порядка вычислений типами) как раз и нужна за тем, чтобы не задумываться - то есть если нам хочется узнать, что и как вычисляется, то нам в этом случае не надо исследовать control-flow, достаточно посмотреть на тип выражения.
Еще можно вспомнить о том, что бОльшая часть юзкейзов лени покрывается ленивыми структурами. В этом смысле какой-нибудь map для списка не должен писаться руками - он должен быть сгенерирован автоматически, исходя из определения АТД "List" и генерализованного определения map для произвольного АТД (как, например, это можно делать в Clean). Для ленивого списка мы автоматически получим ленивый map, для энергичного списка - энергичный map, а переход между способами вычисления будет выглядеть как явное преобразование типа соответствующей структуры.
no subject
no subject
no subject
Проблем с оптимизацией ленивой программы не более, чем проблем с оптимизацией программы на C под Cell BE. Со сложностью то же самое.
Мой подход состоит в экономии времени программиста, чтобы тот совершил больше полезных для понимания предметной области ошибок, а не оптимизировал ещё не написанную программу.
no subject
Начнем сызнова - ваш тезис, как я понимаю, состоит в следующем: ленивый порядок экономит время программиста, поскольку делать выводы о ходе вычисления проще при ленивом порядке.
Здесь есть посылка (делать вывод о ходе вычисления проще при ленивом порядке) и следствие (программист экономит время).
Чтобы следствие получилось верным, надо показать, что верна посылка. Но тут-то и возникает проблема - есть известные факты, которые посылку опровергают. То есть программист, может, время и экономит - но явно не потому, что в ленивом порядке делать выводы о ходе программы проще - т.к. известно, что делать эти выводы при ленивом порядке _сложнее_.
no subject
Вот тут дилемма.
Стоит ли нашему читателю верить Валентину Будаеву или Джону Хьюджесу и Леннарту Аугустссону?
Вадлер, кстати, утверждает дуальность call-by-name и call-by-value. Поэтому на статью с показанной дуальностью call-by-value и call-by-need я бы хотел посмотреть.
И ещё хочу попросить у вас ссылку на статью, которая показывает повышение модульности программ на энергичном языке по сравнению с ленивым. WhyFP Джона Хьюджеса показывает повышение модульности программ только для ленивых языков, надо исправить это упущение.
no subject
А зачем кому-то верить? Я предпочитаю смотреть на экспериментальные факты, а не на чьи-то мнения и статьи (которые тоже суть не более чем мнения). А экспериментальные факты таковы, что при оценке сложности и оптимизации программ ленивый порядок не упрощает, а усложняет reasoning.
> И ещё хочу попросить у вас ссылку на статью, которая показывает повышение модульности программ на энергичном языке по сравнению с ленивым. WhyFP Джона Хьюджеса показывает повышение модульности программ только для ленивых языков, надо исправить это упущение.
Во-первых, это статья о том, как FP поднимает модульность в языках вроде хаскеля. К другим ЯП сделанные в статье выводы, конечно же, неприменимы. Во-вторых, статья рекламная - а энергичному порядку реклама не требуется, Это лень на данный момент маргинальна.В-третьих, я могу ошибаться (вы меня тогда поправьте), но вот тот же Саймон Пейтон-Джонс как-то высказывался на тему того, что лучше было бы хаскелю быть энергичным, нет?
> Поэтому на статью с показанной дуальностью call-by-value и call-by-need я бы хотел посмотреть.
call-by-need и call-by-name изоморфны в обсуждаемом смысле.
no subject
Неверно. Рассуждения о программе усложняются, если пытаться использовать императивный способ рассуждений, основанный на понятии "ход вычислений".
Если же использовать семантику Скотта, то рассуждения становятся проще в разы (а то и в десятки раз).
no subject
От того, что вы белое назовете черным, оно не станет таковым. Проблемы с оценкой сложности ленивых программ - известный факт.
> Если же использовать семантику Скотта, то рассуждения становятся проще в разы (а то и в десятки раз).
Было бы неплохо продемонстрировать этот тезис на каком-нибудь простом примере. Ну, например, докажите в семантике Скотта ассоциативность ф-и append.
no subject
Фу, как некрасиво. Только что говорили вообще про рассуждения о программе — и вдруг спрыгиваете на оценку сложности.
> Ну, например, докажите в семантике Скотта ассоциативность ф-и append.
Это которая в Хаскеле (++)? Конкатенация списков?
Пожалуйста.
Определение:
append [] ys = ys
append (x:xs) ys = x : append xs ys
Требуется доказать:
append xs (append ys zs) = append (append xs ys) zs
Расшифровка определения: если положить
t f [] ys = ys
t f (x:xs) ys = x : f xs ys
то append — наименьшая неподвижная точка функции t, то есть, наименьшая f, для которой t f = f.
Далее, если f такова, что f xs (append ys zs) = append (f xs ys) zs, то t f тоже удовлетворяет этому условию, так как
t f [] (append ys zs) = append ys zs = append (t f xs yz) zs
t f (x:xs) (append ys zs) = x : f xs (append ys zs) = x : append (f xs ys) zs = append (x : f xs ys) zs = append (t f (x:xs) ys) zs
Функция (_|_) этому условию удовлетворяет:
(_|_) xs (append ys zs) = (_|_) = append (_|_) zs = append ((_|_) xs ys) zs
Значит, условие удовлетворяется для tn(_|_) при любом натуральном n. В силу непрерывности обеих его частей по f, оно удовлетворяется также и для supntn(_|_) — а это и есть append.
(no subject)
(Anonymous) - 2012-11-15 04:46 (UTC) - Expand(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
Действительно, СПЖ сказал в интервью, что чистота важнее порядка выполнения и что "следующий Хаскель" может быть и энергичным. Просто проще всего сделать язык чистым с помощью ленивого порядка выполнения.
Который, к тому же, ещё и удобней для программирования.
Насчёт маргинальности... По-моему, умного человека смущает не количество единомышленников, а их качество. Мне нравится Haskell community.
Прошу прощения, но упомянутые вами "эксперименты" пока выглядят всего лишь как ещё одно мнение. Эксперименты должны иметь результаты в виде цифр. Вот таковые про Хаскель и энергичные языки.
И я хочу увидеть чьё-то ещё мнение насчёт изоморфизма call-by-value и call-by-need. Только вашего мне недостаточно. Вы рассматриваете этот пока ещё не существующий для меня дуализм на слишком низком уровне.
no subject
> Вот таковые про Хаскель и энергичные языки.
Вы сами догадаетесь, куда следует засунуть статистические эксперименты без обоснования репрезентативности выборки, или вам подсказать?
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
(no subject)
no subject
Фактически, вы сделали следующее:
map = tmp
теперь если я хочу сделать map энергичным, то просто переопределяю tmp, а реализацию map менять не надо!
Ну так это работает и с энергичным и с ленивым порядком :)
no subject
Ленивое ЛИ Тьринг полно. Значит, в нем можно реализовать force.
В приведенных мной примерах это и делается.
no subject
Энергичное тоже :)
> Значит, в нем можно реализовать force.
Нет, нельзя. условно говоря, delay/force нельзя реализовать в энергичном/ленивом ЯП. С тьюринг-полнотой это не связано - тьюринг-полнота о вычислимости, а не о выразительности.
С точки зрения тьюринг-полноты - ну вы if, напишите, а вот сделать так, чтобы он работал как нормальный if (то есть на булевых значениях) способа никакого нет. Хотя это вобщем-то не важно.