metaclass: (дзедline)
В очередной раз, в связи с макросами подниму свой любимый вопрос:
Можно ли поиметь в языках типа скалы строгую типизацию, не объявляя типы записей заранее?

Идея в следующем: у меня в Clojure большая часть DSL основана на том, что я могу в любое место описания строк-колонок-ячеек отчета (условно говоря, Excel-like таблица фиксированной формы, заполняемая автоматом из проводок) в любой момент добавить атрибут типа :skip-in-vat true и обработать его. При этом мне нужно это изменить ровно в двух местах - описание документа ("данные") и расчетный алгоритм ("код"). Типов тут нет, а вместо них - структуры данных, скомбинированные из словарей, массивов и атомарных данных.

Но с динамически типизированными языками, а особенно с Clojure с ее destructring и прагматичным подходам к совместимости типов имеется постоянно проблема вида "сунул лишние скобки, на место числа попал массив и через 100500 вызовов когда дело дошло до суммирования, оператор + сдох от попытки просуммировать ссылку на массив со стек-трейсом на три страницы". Причем если мне такие ошибки чинить достаточно легко, то менее опытным коллегам это вырывает мозг.

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

Кроме того, часто хочется такого: "тип записи создается в SQL запросе и далее используется в функции, обрабатывающей результат запроса". В clojure это опять же - словарь, с кейвордами в качестве ключей.

Языки же кроме F#, Scala и Clojure можно не рассматривать вообще - на них аналогичные задачи или сводятся к "наняли 100 ртишников по одному на объект предметной области и написали вручную" или к "написали самодельный лисп с хаскелем на дельфи/C#" или к "используем безумные ORM с еще более дикими, чем SQL языками и внешними декларативными описаниями".
Т.е. я не говорю, что они не пригодны - но затраты ресусов на решение задачи на таких языках заметно больше.
metaclass: (Default)
Самоочевидно ли то, что с помощью filter/map/fold можно реализовать бухгалтерскую отчетность более простым и очевидным образом, чем с помощью select .. where .. group by?

Нет, наверно я хотел задать не этот вопрос. Правильный вопрос: сколько в час денег попросит человек, способный за неделю-две разобраться в вышеописанном вопросе?
metaclass: (Default)
и синтеза дизайна системы?
Тут народ вопросом задается: http://guamoka.livejournal.com/1047171.html

Я вот думаю, что не везде требуют соблюдать вуду-процессы с артефактами-uml-подробными спецификациями и прочим, особенно там, где не нужно держать сотни человек на работе, из-за чего явной надобности формализовать и систематизировать методы анализа и дизайна с функциональщиной до сих пор не возникало.
Но вообще бы формализация не помешала - было бы проще объяснять как это работает. А то я затрудняюсь описать, как у меня при взгляде на требования пользователей в голове сразу обычно возникает готовая структура программы, из-за чего процесс дизайна плохо объясняем и не отчуждаем.
metaclass: (Default)
Макрос with-db-comment выполняет указанную функцию с параметрами в контексте коннект+транзакция, с логом комментария к транзакции в БД.
dump-seq-debug скармливает последовательность в log4j для отладки.

вот такое падает с NPE:
(with-db-comment "(get-subaccounts 20)"
(dump-seq-debug (get-subaccounts "20")))

вот такое работает:
(with-db-comment "(get-subaccounts 20)"
dump-seq-debug (get-subaccounts "20"))

Можно ли увидеть разницу с первого раза и понять, откуда там NPE? :)

Вот эта содомия с лишними или пропущенными скобками, не обнаруживаемыми компилятором работу с кложурелиспами делает немного неудобной.
И практически не пригодной для осмысленного использования людьми без встроенной типовыводилки в голове.
metaclass: (Default)
Scala - это Haskell в жабьей шкуре?

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

Язык знатно безумный, я почти Programming in Scala дочитал. И кое-какие вещи там сильно похожи на решение некоторых проблем с наследованием и зависимостями типов друг от друга, которых мне не хватало в дельфи и дотнетах :)
metaclass: (Default)
fp, cмерть мерзкая от монад, хаскель, штанга, гроб, гроб, кладбище
http://juick.com/2165512

Можно ли на всем этом сделать так: https://gist.github.com/4292029
И чтобы goodProcessingFunction можно было нормально комбинировать из отдельных кусков, вплоть до того, что явно определить точки, где данные юзера становятся данными для девайса и наоборот.
Или например, обощить это, прикрутив еще и какой-нибудь tcp сервер.

Т.е. у нас есть несколько независимых IO каналов, каждый со своими форматами данных, на каждый канал прикрутить сменный парсер-сериализатор, чтобы в ядро бизнес-логики этот канал приходил уже в виде значений нормальных типов.
А потом еще захочется хранить в бизнес-логике состояние, подключаться к БД и все это, по-моему, нахрен умрет под грузом типов и слоев монад.
metaclass: (дзедline)
http://juick.com/dmz/2163653
Алгебраические типы данных и сопоставление с образцом - то, чего дичайше не хватает в "мейнстримных языках".
В принципе, ничто не мешает закатить солнце вручную - например, написать мелкий кодогенератор, который будет из описания типа генерить код класса-типа и его наследников-вариантов и паттерн-матчинг на дельфи-C#-жабе-прочем. Но это элемент зла, проще уж F# использовать.
metaclass: (дзедline)
http://tonsky.livejournal.com/271470.html
Все написано правильно. А теперь про недостатки:
1) совершенно невменяемые стек-трейсы(как и везде, где есть ленивые коллекции)
2) очень легко где-нибудь сунуть лишние [] или забыть их и вектор чисел становится внезапно вектором векторов, или наоборот. В общем, сунуть объект не того типа. При этом, в силу ленивости и вообще абстракций, это вызовет адов стектрейс совершенно не там где это началось.
metaclass: (дзедline)
http://juick.com/dmz/2147369#53
а мне вот, допустим, ваши реплики неприятны и потенциально вредят бизнесу. и если ко мне через месяц придет заказчик и скажет --- какого хуя вы вот мне софт для управления дц пишете на хаскелле, я тут читал автора ёрливидео, и он говорит, что хаскель --- говно, переписывайте всё нахуй на эрланге --- это будет уже прямой убыток. это маловероятно, но вполне может пойти в том ключе.
metaclass: (Default)
Основной критерий выбора технологий программирования: "Чтобы вас можно было заменить на васю, не знающего языка и он мог прочесть код": http://ugenk.livejournal.com/188023.html
metaclass: (Default)
Вот тут http://levgem.livejournal.com/420910.html задают вопрос, который меня тоже сильно интересует - есть ли такая высокоуровневая операция, которая бы позволила абстрагировать обработку элемента (упорядоченного) множества в контексте взаимодействия этого элемента с его соседями.
Вроде [livejournal.com profile] antilamer что-то похожее писал про комонады, но мне без конкретной задачи сложно осознать, как это использовать.
Вот например map, filter, fold - я их понял от входа, потому что очевидная аналогия с SQL запросами - select, where, group by (и прочие агрегаты).
У обработки в контексте понятная мне аналогия - это, например, window functions в SQL, скользящее среднее, интеграторы-дифференциаторы и прочие фильтры-свертки в DSP, но вот их я внятным образом с функциональщиной сопоставить не могу.

PS: клеточные автоматы и комонады: http://blog.sigfpe.com/2006/12/evaluating-cellular-automata-is.html Клеточный автомат тоже подвид фильтра поверх скользящего окна.
И функции поверх потоков: http://blog.sigfpe.com/2006/06/monads-kleisli-arrows-comonads-and.html
metaclass: (Default)
https://gist.github.com/4037621
Если убрать заворачивание промежуточных результатов reduce в vec (строка 15), которое делает из ленивого результата map энергичный - сей сабж дохнет с StackOverflowError, в трейсе которого много-много раз повторяется следующее:

clojure.core/map/fn--4094 (core.clj:2443)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:60)
clojure.lang.RT.seq (RT.java:473)
clojure.core/seq (core.clj:133)

Scala

Nov. 6th, 2012 04:15 am
metaclass: (Default)
Читаю книжку Одерского, до основной шизы еще не добрался, но такое ощущение, что в скале чрезмерно много синтаксического сахара. Типа "тут вы можете скобки опустить, а тут вместо скобок использовать фигурные скобки, а тут мы прямо в параметрах класса сделаем их полями, а в multiline string literal вы можете сделать отступ и stripMargin" и прочая и прочая в том же духе.
Основное из этого, видимо - function literals и вызов методов в стиле a methodName b, без точек и скобок, что делает код более лаконичным, одновременно позволяя при желании превратить код в нечитабельный ад.

Заодно по наводке [livejournal.com profile] 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

По-моему, это уже достаточно сложно, чтобы увлечь психов и стать новыми крестиками. Вот [livejournal.com profile] xeno_by еще приделает макросы - и совсем хорошо станет.
metaclass: (Default)
[livejournal.com profile] plumqqz доставил нам очередную ссылку на ужасы обсуждения БД на хабре. Сама статья еще куда ни шло, за исключением представления constraints как мега-фичи (вроде это основа основ любой БД). В комментариях, само собой, дикий ад, трэш, угар, содомия, коровники, заборы, катаформизм хабракармы и голые бизнес-аналитекши.

Самое ужасное там - это когда структуре данных отказывают в праве считаться частью бизнес-логики, упирая на то, что "надо же абстрагироваться от хранилища".
При этом, даже если добится этого абстрагирования - то все равно структура данных будет в памяти, в виде графа объектов, будет нужен дополнительный код по интеграции этой структуры с тем, что живет в БД, и никуда мы от структуры данных не денемся. А уж про то, можно ли считать констрейнты (в т.ч. и сложные, выражаемые только в виде триггеров) частью типов данных - можно дискутировать вечно. По крайней мере, check и foreign key constraints это точно часть типа данных, в случае FK - это еще и зависимые типы, реализованные в понятном виде. В случае unique constraints - уже сложнее, но по идее, тоже зависимый тип (зависит от данных таблицы, в которой он используется).

Так вот, я считаю, что структура данных для бизнес-логики гораздо более важна, чем собственно код. Если вам скажут, что теперь операция с кодом "777029" не облагается НДС - вам всего лишь нужно добавить веточку в паттерн-матчинг. Структура программы от этого не изменится и коллегам вы билд нахрен не сломаете.
А если окажется, что для того, чтобы узнать, как обрабатывается операция, вам нужно заглянуть в настройки в СУБД - то внезапно, в гламурно-причесанной функционально-иммутабельной функции проверки условий появляется грязная монада IO, провайдеры коннектов к БД, автоматическое управление транзакциями, пул коннектов, кэши и прочая черняга и структура данных (к коей я отношу так же и сигнатуры функций) меняется весьма заметно. Альтернативный вариант - оставить функцию чистой, но добавить к ней еще параметров, передаваемых извне, проверить код коллег, записать в трекер и рассказать, что теперь без передачи в нее оккультного набора параметров функция больше не заработает.
metaclass: (Default)
(#(% %) #(% %)) - StackOverflow на кложуре
((fn [x] (x x)) (fn [x] (x x))) - StackOverflow на кложуре (более явная запись предущего)
на хаскеле даже на \x -> x x сразу ругается тайпчекер

(λx.xx)(λx.xx) - это оно же?
metaclass: (Default)
Вчера [livejournal.com profile] ivan_gandhi сделал замечание что я, пользуясь динамически типизированной кложурью, при этом требую, чтобы в Java проверяли входные параметры на валидность. (Если что, проверка валидности в дотнете есть на каждом шагу, а объяснения вида "экономят циклы и не делаю проверки" в контексте жабы, тяжелого железа, JIT и прочего звучат крайне странно).
Собирался на эту тему устроить срач с утра, но [livejournal.com profile] thedeemon уже начал, так что я продолжу :)

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

Например, я хочу использовать кортеж с именованными полями (потому что позиционные кортежи нихера нечитабельны и их тип вида int*string*smallint*money*bool*Chervie ни о о чем не говорят). От входа в F# при этом нужно:
1) объявить этот чертов record где-то
2) сослаться на модуль с объявлением везде где он нужен
3) создавать экземпляры рекорда кривопачвярными конструкциями, причем оставить поля значениями по умолчанию нельзя.
4) паттерн матчинг с декомпозицией вроде не работает с рекордами.

Хаскель сразу закапываем - там на каждый случай имеется 3-4 расширения и 10 пакетов в hackage различной степени недоделанности, идиоматический подход - писать в point-free style, чтобы коллеги не разобрались, а работать в продакшене можно только с теми сторонними библиотеками, которые я могу сам починить.

При этом, у меня при работе с оперденями постоянно ситуации вида: есть запись с тремя полями, полученная из БД, мне нужно произвести обработку этой записи и добавить результат обработки в виде четвертого поля, получив новый тип записи.
Я НЕ хочу объявлять каждый раз такое руками и в Clojure это делается элементарно, добавлением нового ключа в map в функции-обработчике записей.

При этом РЕАЛЬНО динамическую типизацию я не использую. Она мне почти не нужна, потому что единственная ситуация, где вменяемый человек будет на одном цикле биндить к имени число, на втором строку, на третьем - список записей - это когда по условию задачи нужна, например, EAV-модель во все поля. И то - обычно EAV делается от безысходности, потому что пользователь не может нормально работать со схемой БД, а задача требует чего-нибудь вроде "добавить к части записей атрибут "фаза луны в которую производилась приемка товара"". В норме должны быть зависимые типы и миграции и пользователи бы пользовались той же системой типов что и разработчик.
Т.е. нормальный вывод типов - это когда программа берет типы из тут же описанного SQL-запроса, а рекорды расширяемые и объявлять их не нужно.

Второй use-case, где "вроде бы динамическая типизация" - это когда я делаю документы в виде кложурных структур данных, подгоняя комбинации списков-мапов-массивов-множеств под предметную область. В кложуре же это делается в лоб, а в хаскеле в один список не положишь три разных по структуре(типу) раздела документа. Но на самом деле, то что я делаю в кложури - это просто алгебраический тип данных "для бедных", без объявления заранее и без явно выделенных-именованных конструкторов данных. Если бы была возможность делать расширяемые и объявляемые по месту типы данных (чтобы каждый раз при разработке не переключаться между объявлением типа и конструированием данных по этому типу) - то было бы то же самое что в кложури - но статически типизированное.

PS: На ту же тему: http://justy-tylor.livejournal.com/190153.html
metaclass: (Default)
Вспомнил один срач на тему однопроходных компиляторов, где Steve Yegge критиковал Clojure за то, что в ней объявления видны не во всем модуле, а только ниже объявления. (Ну, за исключением declare которые что-то вроде forward-объявлений).
Сижу приделываю новую фичу к кодогенератору на F# - и таки внезапно оказывается, что это не только в Clojure, но так же и F#, и, что самое печальное, - в долбаном SQL, который я генерирую.
Сижу вот, сортирую объекты из которых генерируется SQL по зависимостям.

А как с этим дела обстоят в Scala?
Я тут подумываю, что надо бы провести сравнение F# и Scala на моих задачах, все равно уже полная работа JVM и жаб, так может, выводилка типов в Scala для меня окажется более приемлемой, чем дикий ад в F# (теперь я понимаю, почему его [livejournal.com profile] thesz критикует). Ну и макросы в скале [livejournal.com profile] xeno_by прикрутил вроде уже.
Хотя единственное, что мне приходит в голову на тему приличного использования макросов - это при их выполнении долбится в БД или модель этой БД и генерировать код.
metaclass: (Default)
http://lex-kravetski.livejournal.com/424713.html
Все сомнения о том, что какие-то штуки не будут работать, всё развалится в самый последний момент, возникнут непредвиденные сложности с языком, будет чего-то важного не хватать и так далее, они логичны и обоснованы, однако эксперимент показал, в случае со Scala такого не происходит. За полгода разработки я не встретил ни одной непреодолимой сложности, всё работало, из Java вызывалось и так далее.

Реальный выигрыш будет в основном для тех, кто уже сейчас пишет по сути на Scala, только под Явой. То есть использует похожие концепции для выражения своих мыслей и понимает эти концепции. Тот, кто в некотором смысле сам для себя их «изобрёл». В этом случае он получает инструмент, при помощи которого пользоваться ими на порядок проще, и начинает переться. Те же, кто копипастил, не видят перемен к лучшему — какая разница, где копипастить? Они видят только, что синтаксис другой, а их коллеги повсеместно используют какую-то долбанную магию вуду.

Все то же самое, дословно, можно сказать про Clojure или F#.
metaclass: (Default)
http://blog.jelastic.com/2012/07/24/functional-programming-is-a-ghetto/
So why is functional programming, despite its virtues, a ghetto? The answer is that we tend to insist on good design, to such a degree that we avoid taking jobs where we’re at risk of having to deal with bad designs.

PS: В статье позитивная айседовщина. "IDE не нужны, потому что на продакшен сервере за тридевять земель вам они не помогут", "только идиоты начинают разработку на жабе или С++ в 2012 году" и прочее такое.

Еще того же автора: http://michaelochurch.wordpress.com/2012/04/13/java-shop-politics/

Profile

metaclass: (Default)
metaclass

April 2017

S M T W T F S
      1
2345678
9101112 131415
16171819202122
23242526272829
30      

Syndicate

RSS Atom

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 25th, 2017 12:43 am
Powered by Dreamwidth Studios