Home
Objective Caml
ocaml@conference.jabber.ru
Пятница, 20 января 2012< ^ >
f[x] установил(а) тему: OCaml / ОКамл / Камль -- http://caml.inria.fr | http://camlunity.ru/ (теперь с git доступом!) | Верблюды грязи не боятся! | release crap, enjoy NIH | репортьте баги официальным дилерам | ocaml мёртв и тормозит, move on | stdlib only? - ССЗБ | Fight FUD with fire
Конфигурация комнаты
Участники комнаты

GMT+4
[00:00:24] <gds> такой iter можно изобразить поверх того, что предлагаю.
в общем, либо camomile как готовый вариант, либо мог бы накодить подобное в кадастре, если надо.  мне-то точно надо (пригодится в ближайшем будущем, кодить по-любому буду).
[00:00:49] <bobry> а почему не хочешь camomile?
[00:01:49] <gds> потому что накодить такую простую функцию несложно, стандарт utf8 фиксирован, всю camomile не везде нужно тащить, а кадастр у меня тащится почти везде.
[00:02:35] <bobry> а как хранить планируешь? чисто -- не чисто?
[00:04:47] <gds> хранить -- в string, но чисто.  у модуля, который заменит String при open Strings.Utf8, оторву всё ненужное, в том числе set.
[00:05:59] <gds> то есть, уже налепил модулей (в том числе Utf8), которые дают только иммутабельные строки.  а вдобавок к простым однобайтовым строкам, у Utf8 оторвал также get, оставил только append и ещё по мелочи, "of_bytes" / "to_bytes", как-то так.
[00:07:20] <gds> а вот насчёт чистого хранения -- оооо, сколько я думал.  Если хотеть append в амортизированное O(1), то сложно, а то, что просто, по константе не очень хорошо.
[00:08:13] <bobry> а как можно сделать append чтобы О(1) даже если с константой?
[00:08:20] bobry еще не очень далеко продвинулся в окасаке
[00:08:23] <gds> в общем, задача сводится к deques (внутри -- uchar, куски строк, пофиг), которые поддерживают быстрый доступ -- к голове, к хвосту, по индексу.
[00:09:34] <gds> вот собственно в окасаке и описано, делают там хитрые деревья, полиморфную рекурсию, так называемый "ленивый рекурсивный спуск", который амортизированно даёт O(1).
[00:10:00] <bobry> звучит круто, а как оно у него обзывается?
[00:10:11] <bobry> кстате gds, ты кадастр то пошто пилишь? для себя?
[00:13:48] <gds> чорт, не могу найти окасаку.
кстати, ещё есть http://cstheory.stackexchange.com/questions/1539/whats-new-in-purely-functional-data-structures-since-okasaki
[00:13:58] <bobry> ага, видел этот тред
[00:14:19] <bobry> intmap во всю в х-ле используется, в platform в смысле
[00:15:07] <gds> в общем, "lazy recursive slowdown" это ключевые слова.  Там он делает deque из пяти элементов, F A M B R, и использует лентяйку.  Вот оно O(1) в append.  На словах.  На деле чото не ок вышло, вроде.
[00:16:24] <gds> кадастр -- для себя.  там много всего набросано, из того, что мне постоянно нужно.  динамические типы (runtime type info), манатки и около, расширенные моноеды.
[00:19:44] <gds> вот нашёл недавнее, что делал, http://paste.in.ua/3735/ , но там хня.
[00:20:35] <gds> по тупому n*cons + n*tail проигрывает спискам с таким серьёзным отсосом, что дальше уже мало что хотелось делать.
[00:21:39] <gds> да и нормальный "гибрид" нормальных списков с окасакиными структурами тоже не получается, везде какие-то недостатки.
[00:28:10] <gds> ещё можно поискать "ocaml fingertrees" как очередное доказательство того, что камло сдохло.
[00:29:16] <bobry> а, это похоже catanable deques, ты про них говорил
[00:29:35] <bobry> а как runtime type info работает? это вообще возможно?
[00:29:46] bobry нашел реализацию алгоритма укконена для камло -- а ты говоришь сдох
[00:37:32] <gds> показывай алгоритм!
[00:39:09] <bobry> http://www.lri.fr/~filliatr/ftp/ocaml/ds/suffix_tree.ml
[00:39:47] <bobry> есть еще статейка про х-ль, но там эти суффиксные деревья строят в O(n*logn) amortized time
[00:39:49] <gds> runtime type info -- очень просто.  Если вкратце, с каждой "информацией о типе" связана своя ref (option 'a).  А каждое "нетипизированное значение" является функцией unit -> unit, которая в closure хранит собственно значение, и при вызове пишет его в данную ref.  То есть, имея информацию о типе (в том числе get из этой ref), и имея "нетипизированное значение", можно получить типизированное значение, вполне так чисто.
[00:39:54] <bobry> что разумеется не так кошерно как O(n) у укконена
[00:40:04] ftrvxmtrx вышел(а) из комнаты
[00:41:24] <gds> про алгоритм -- непонятно, но это 1. потому что в целом туплю в последние пару дней, 2. не читал оригинальных папиров.
[00:41:50] <bobry> этот алгоритм и при чтении папира не особо понятен ..
[00:42:07] <bobry> хотя считается самым простым в своем классе )
[00:42:27] ftrvxmtrx вошёл(а) в комнату
[00:42:42] <gds> будь мозга побольше, попросил бы папир.  но не попрошу, есть и тупые дела, которые попадают ниже планки текущего интеллекта, и которые тоже нужно делать.  тот же шелл.
[00:42:43] <bobry> а для чего ты этот финт с runtime types пользуешь?
[00:48:55] Kakadu вышел(а) из комнаты
[00:48:56] <gds> rtti -- да для чего угодно.  например, для обобщённых алгоритмов, в которых не хочется иметь тип, параметризованный по разному количеству параметров (т.е. под функтор не закатаешь), и в этом случае проще сделать мономорфно, поверх ubox (untyped boxed value).  далее, использую то, что в rtti у меня на самом деле что-то типа словаря, и там определяю (пока что) функции to_json и of_json, и сам по себе кадастр не требует наличия json-wheel, но, если он есть, и если типы известны софтине, использующей кадастр и rtti, будет тебе сериализация.  кроме того, rtti полезно тем, что можно, имея различные cmp/eq/hash/show/whatever для типа, и алгоритм работы с каким-нибудь list 'a, построить из ti 'a значение ti (list 'a).  например, для списков, лексикографически сравнивающее их при вызове ti_list#cmp.  далее планирую использовать в парвеле -- там "процесс" (в смысле парвела), принимающий сообщения, будет передавать свой ti 'a, если принимает сообщения с типом 'a, и на основании инфы в ti 'a будет определяться (при get_pid каком-нибудь, вызванным отправляющей сторонй), какие форматы и версии типов данных умеет десериализировать данный "процесс".
[01:04:46] <gds> кроме того, совсем забыл, что разработал также способ разрушать значения конкретных типов, например, записей и вариантных типов.  в результате на каждый тип нужна только одна разрушающая функция, из которой генерируются cmp/eq/hash/show по определённым правилам, но нет нужды разрушать пары значений, хватает разрушения одного из значений.  (хотя вполне можно оверрайдить то, что нагенерилось -- предоставить свои eq и hash, оставив остальные функции как есть.)
[01:05:55] <gds> то есть, из функции, разрушающей одно значение, я вывожу как "одноместные" функции наподобие show : t -> string, так и двуместные, наподобие eq : t -> t -> bool.
[01:08:00] ftrvxmtrx вышел(а) из комнаты
[01:10:38] ftrvxmtrx вошёл(а) в комнату
[01:15:56] <gds> а мономорфность ubox очень полезна -- например, можно сделать очень тупой тип, описывающий иерархию веб-сервисов, берущих по сути разные типы (инфа о типах -- в of_json).  или можно легко сделать описание грамматики, предоставив заботиться о типах пользователя, а самим оперируя с абстрактными ubox.
[01:25:14] <gds> только, блеять, как же было сложно обо всём этом додумываться самому, когда никто не помогал.  обычно у людей так -- "если строгая типизация -- известны все типы" и "если типизация нестрогая -- лови сам свои проблемы".  а вот про гибриды мало кто думает.  и вот, на языках со строгой типизацией (особенно на функциональщине) пишут унылое говно, корректное, но мало нужное людям (компиляторы какие-то), на языках с динамической типизацией пишут нужное людям, но сдыхают в корчах от ошибок типов.  какой-нибудь баланс, может, внести надо?
[01:29:04] Typhon вошёл(а) в комнату
[02:12:21] bobry вышел(а) из комнаты
[02:18:53] <klapaucius> Ну так и не нужно было самому догадываться, а использовать чужой опыт. В хаскеле несколько лет назад это был популярный подход - динамика с Any и unsafeCoerce, rtti на Data/Typeable, Data.Dynamic и syb. Но сейчас это уже не модно и не в струе - более перспективны полностью статические дженерики для масс/types a-la carte и тд
[03:07:19] <gds> klapaucius: Any/unsafeCoerce -- что они делают?  Остальное примерно понятно (понятны концепции).  Но в х-е чуть по-другому обстоят дела, напрямую перенимать опыт не получается.  Например, многое из того, что я сделал, отображается на те же тайпклассы, которых в окамле нет, и это тоже приходилось лепить из динамического говна и динамических палок.
[03:36:27] letrec вошёл(а) в комнату
[04:51:11] letrec вышел(а) из комнаты
[04:54:36] ftrvxmtrx вышел(а) из комнаты
[09:38:46] bobry вошёл(а) в комнату
[09:45:26] <bobry> gds: а примеры кода с rtti смотреть в кадастре?
[10:05:48] bobry вышел(а) из комнаты
[10:50:19] bobry вошёл(а) в комнату
[11:07:21] <bobry> ого, (подглядел в #ocaml) — камло используют в cancer research center! для построения филогенетических деревьев, nice! https://github.com/matsen/pplacer
[11:08:27] ftrvxmtrx вошёл(а) в комнату
[11:15:55] ftrvxmtrx вышел(а) из комнаты
[11:54:47] ftrvxmtrx вошёл(а) в комнату
[12:08:48] Kakadu вошёл(а) в комнату
[12:30:52] ermine вошёл(а) в комнату
[13:59:05] <f[x]> utf итерация есть в extlib
[14:10:27] shaggie вошёл(а) в комнату
[14:20:31] Typhon вышел(а) из комнаты
[14:45:20] <gds> bobry: да, rtti -- там.  есть ещё в паре проектов, но один пока не опубликован, а другие не будут опубликованы вообще.
[16:03:05] ftrvxmtrx вышел(а) из комнаты
[16:16:46] letrec вошёл(а) в комнату
[16:16:53] letrec вышел(а) из комнаты
[16:17:10] letrec вошёл(а) в комнату
[16:21:54] f[x] вышел(а) из комнаты
[16:25:29] f[x] вошёл(а) в комнату
[16:39:29] ftrvxmtrx вошёл(а) в комнату
[16:57:51] <letrec> gds: а что можно сделать на тайпклассах такого, что в камле не получится?
[16:58:25] <letrec> я думал оно эквивалентно по выразительным возможностям
[16:59:31] <gds> letrec: в камле всё получится, только по-другому, не обязательно тайпклассами.  вот, например, по наводке klapaucius посмотрел "data types a la carte" -- http://www.cs.ru.nl/~wouters/Publications/DataTypesALaCarte.pdf -- там тайпклассы используются для решения expression problem и для подтипизации, что в камле проще решить через полиморфные варианты и открытую рекурсию.
[17:00:40] <gds> то есть, тут скорее не "можно / нельзя", а "нужно ли в камле делать это через эмуляцию тайпклассов или проще сделать по-другому".
[17:11:02] <letrec> меня просто смутило динамическое говно в твоём обходе отсутствия тайпклассов
[17:12:41] <letrec> я как-то читал ML Modules and Haskell Type Classes: A Constructive Comparison понял далеко не всё, но основная идея, что всё решается нормально статичски типизированным образом
[17:16:32] <gds> letrec: статически всё решить можно, но тогда надо кодогенерить из каждого определения типа.  а это -- camlp4 и подобные расширения синтаксиса, которые мне жутко не нравятся.  это личное.  но так -- было бы возможно.  но я не хотел так.
кроме того, кое-что не очень решается, у меня же не только тайпклассы, у меня кое-что чуть мощнее в плане расширяемости -- например, внешние зависимости (например, json-wheel) тащатся только при их непосредственном использовании.  кроме того, одна из задач, которую я решал, это использование подобных rtti для нужд межпроцессовой коммуникации, где принципиально невозможно проанализировать все-все процессы, участвующие во взаимодействии.
[17:23:02] <letrec> а как data Expr f = In (f (Expr f )) на окамле записать?
[17:23:41] <gds> letrec: если любишь функторы/алгебры, поломай моск на http://alain.frisch.fr/soft#recursive , понравится.  навряд ли раньше видел.  а там, если будет желание применить функторы (в смысле ТК) для добрых дел, посмотри https://github.com/camlunity/kamlo_wiki/blob/master/CrazyIdeas.md в главе "ocaml on-disk datastructures".
[17:24:28] <gds> letrec: видимо, записывается как функтор (в смысле окамла), берущий сигнатуру с type 'a f.  но сходу не знаю.  тоже думал поиграться с этим :)
[17:28:28] gds afk 2h.  пешыте мне11111
[18:04:34] bobry вышел(а) из комнаты
[18:11:33] <Kakadu> Печаль, на работе печеньки закончились. Теперь приходится тарталетки жрать.
[19:05:25] <letrec> http://caml.inria.fr/mantis/view.php?id=5236 молодцы
[19:21:23] Kakadu вышел(а) из комнаты
[19:30:55] <gds> факт.
[20:02:45] Kakadu вошёл(а) в комнату
[20:15:28] <letrec> а вот так
let rec sum l =
  let rec sum a l = match l with
    | hd::tl -> sum (a + hd) tl
    | [] -> a in
  sum 0 l
shdowing использовать это abuse?
[20:16:18] <f[x]> верхний let rec лучше убрать
[20:16:29] <f[x]> кстати, для этого нет ворнинга?
[20:16:40] <gds> 1. вопрос изначально субъективный, 2. по моему мнению, не abuse, а очень даже нормально.  главное -- консистентность, чтобы не написать в одном случае l, а в другом, например, lst.
[20:17:16] <gds> f[x]: для let rec -- нет, для такого shadowing -- по -w A не включается точно.
[20:17:38] <letrec> кстати да, заметил потом забыл
[20:17:47] <f[x]> "this rec is unused!"
[20:18:31] <gds> f[x]: жжош!
[20:20:10] <letrec> ворнинг для rec был бы в тему
[20:21:08] <gds> а как определить, сознательно он или по ошибке оставлен?
[20:21:33] <letrec> если не используется рекурсивность, то скорее всего по ошибке
[20:22:00] <letrec> как и в обратную сторону
[20:22:56] <letrec> т.е. от рекурсии требуют явность, хорошо бы симметрично требовать того же для нерекурсивного случая
[20:23:23] <gds> let f x = x + 1
let rec(?) f y = if f y > 0 then f (y - 1) else 0
тут rec нужен?
[20:23:58] <gds> ну вот, симметрично "let" явно указывается как "без рекурсии".  "let" vs "let rec" спутать сложно.
[20:24:46] <letrec> но в одном случае это обязательно, а во втором нет
[20:24:54] <letrec> неконсистентность
[20:25:20] <gds> во всех случаях, где нужна рекурсивность, let rec обязательно.  во всех, где рекурсивность не нужна, let обязательно.
[20:25:58] <f[x]> gds: в твоём случае ворнинг не появляется
[20:26:15] <f[x]> ворнинг появляется если let rec f y = if g y > 0 then g (y - 1) else 0
[20:26:17] <gds> f[x]: и не должен, это же валидный и осмысленный камлокод.
[20:26:25] <letrec> в случае let всё менее жёстко - можно использовать 2 варианта, а в случае let rec только один
[20:26:34] <f[x]> s/появляется/должен появляться/
[20:26:55] <gds> > let rec f y = if g y > 0 then g (y - 1) else 0
у меня тут чото ошибка, что я не так делаю?
[20:27:49] <f[x]> я понял, пятница
[20:27:56] <gds> letrec: в случае let используется ровно один вариант (а именно, брать биндинги свыше), в случае let rec используется тоже ровно один вариант (а именно, внести все биндинги, инициированные let rec, в окружение).
[20:27:56] <f[x]> let g x = x
[20:28:02] <f[x]> let rec f y = if g y > 0 then g (y - 1) else 0
[20:28:59] <gds> f[x]: не клеится:
$ ocaml -w A
# let g x = x;;
val g : 'a -> 'a = <fun>
# let rec f y = if g y > 0 then g (y - 1) else 0;;
val f : int -> int = <fun>
#
[20:29:25] <letrec> разве 2ое имя не затеняет 1е?
[20:29:46] <gds> letrec: ты про какой случай?
[20:29:56] <letrec> про твой первый пример
[20:30:08] <letrec> let f x = x + 1
let rec(?) f y = if f y > 0 then f (y - 1) else 0
[20:30:15] <gds> затеняет.  и чо?
[20:30:46] <letrec> получается, что возможно только рекурсивное использование, нет?
[20:30:58] <letrec> на первое же сослаться нельзя
[20:31:08] <gds> недопонимаю.  с rec и без rec это две разные программы.
[20:31:15] <letrec> а на себя без rec тоже
[20:31:52] <gds> как раз, если нет rec, то на первое f и ссылается тело второй функции f.
[20:32:17] <letrec> так оно же затенено
[20:32:33] ftrvxmtrx вышел(а) из комнаты
[20:32:34] <gds> затенено _после_ компиляции let f .
[20:32:48] <f[x]> gds: я говорю что хорошо было бы если был бы в таком случае ворнинг "rec is unused"
[20:33:06] <gds> rec -- это лишь признак "вводить ли описанные привязки в текущее окружение".  Если его нет -- используются старые привязки, доступные _до_ let.  Если оно есть, новые привязки, введённые пачкой определений let rec .. and ..
[20:33:07] <f[x]> gds: это к "не клеится" коммент
[20:33:46] <letrec> т.е. затенение имеет место быть после второго определения? а в самом втором определении его ещё нет?
[20:34:12] <f[x]> я конечно выражаюсь криво, но тут последние 10 минут жестокий тупняк в чате
[20:34:59] <letrec> ну его в пень - лучше разные имена юзать
[20:35:29] <gds> f[x]: нехорошо получится тогда.  1. надо знать типы (может быть include Somemodule перед let, и угадывать, есть ли там функция f).  2. нарушается композиционируемость на уровне исходников, а именно, камло имеет хорошее свойство: "если были два исходника, компилирующиеся по-отдельности, то можно их слить в один исходник в любом порядке, так, что они будут компилироваться и работать так же, как до слияния".
[20:35:59] <f[x]> WHUT??
[20:36:08] <f[x]> это чисто локальное для функции свойство
[20:36:52] <f[x]> если (группа) функция помечена rec но есть функции в этой группе которые не учасвуют в рекурсии
[20:38:12] <gds> letrec: вот смотри, есть какое-то окружение.  Всякие значения, типы, уёмоё.  Компилятор разбирает let [rec].  В случае let для "резолва" окружения используется всё, что было в окружении строго до let.  В случае let rec -- значения из let rec уже есть в окружении, и любая ссылка на них резолвится только в то, что есть в let rec.  То есть, rec -- признак того, добавлять ли текущие привязки в окружение сразу или потом.
[20:38:12] <f[x]> то на такие функции надо ругаться
[20:39:33] <letrec> gds: т.е. начиная с тела определения или после него?
[20:40:52] <letrec> мне профит этой фичи пока кажется сомнительным
[20:41:07] <gds> f[x]: понял твоё предложение.  Но может быть там rec из-за того, что в случае, когда в функцию что-то допишут (в том числе рекурсивный вызов себя), то она должна стать рекурсивной.  Ну и как бы гарантия того, что любой вызов f будет обязан брать именно эту f, а не какую-то другую.
[20:41:50] <f[x]> gds: ну вот когда допишут тогда и ставьте rec
[20:41:56] <f[x]> ты такой код в реале видел?
[20:42:08] <gds> letrec: да, именно, с тела (с тела каждой из привязок) либо после их вычисления.  сомнительно -- может быть, спорить не буду.
[20:42:11] <f[x]> а вот багу с копипастой и переименованием поиметь легко
[20:42:23] <letrec> вот нет перегрузки и хорошо - меньше морщить мозг
[20:42:44] <gds> f[x]: да, сам писал, и если у меня функция обязана ссылаться на себя в случае будущих дописок, то там всегда let rec.
[20:42:45] <letrec> у кого-нибудь есть пример killer применения затенению?
[20:43:22] <f[x]> gds: хм
[20:43:45] <f[x]> т.е. ты пишешь нерекурсивную функция ставя let rec "на будущее"?
[20:44:36] <f[x]> надо пойти пропихнуть такой ворнинг в мантис чтобы ты перестал так делать!
[20:45:13] <letrec> f[x]: +1
[20:47:10] <letrec> вот есть сопутсвующий вопрос на тему эволюции кода: если функцию легко сделать полиморфной, но сейчас от этого проку нет, вы это сделаете?
[20:48:27] <gds> f[x]: да!  если знаю, что функция, в случае чего, может стать рекурсивной.  например, вычислялка eval : expr -> int, когда expr определено как [ Const of int ], но, скорее всего, добавится случай [ Add of expr and expr ].
[20:48:46] <gds> letrec: конечно сделаю.  О полиморфных функциях гораздо легче рассуждать.
[20:49:23] <f[x]> что значит - легко сделать? зависит от причины по которой она неполиморфна
[20:49:54] <f[x]> но вообще проще конечно не мономорфизировать без надобности
[20:50:08] <f[x]> gds: специально для тебя пойду запилю ворнинг!
[20:50:19] <gds> f[x]: и мстя твоя будет страшной!!1111
[20:51:38] <letrec> например вытащить ту часть, которая её делает мономорфной в параметр
[20:52:14] <f[x]> ты меня сфрустрировал!
[20:52:18] <gds> но тут надо думать, не сильно ли хуже будет.  И это путь к абстракционистскому дрочеву.  Если оправдано, то нужно, а для красоты -- хз.
[20:53:01] <letrec> вот я именно об этом - с чего начинается дрочево? :)
[20:53:43] <letrec> в вышеприведённом случае можно (+) передавать параметром на случай, если вдруг, например вычитать решим
[20:53:58] <letrec> правда производительность пострадает
[20:54:10] <letrec> это уже дрочево?
[20:54:27] <gds> с того, что представляешь себе что-то возбуждающее.  Комбинатор вполне подойдёт.  Потом начинаешь представлять, как ты его будешь втыкать в код, какой профит будет, какая ошибкозащищённость!  А потом, тривиально, берёшь руки и абстрагируешь этот код.
[20:55:16] <gds> вычитать решать не надо, несимметрично.  Я бы вообще передавал моноед: type monoid 'a = < zero : 'a ; plus : 'a -> 'a -> 'a > и им сворачивал бы.
[20:56:25] <gds> а потом, когда удар по производительности станет очевидным, легко переписать на мономорфный (+).
[20:57:13] <gds> но с вероятностью 95% он не станет, если, конечно, программа занимается не исключительно суммированием списков целых чисел.
[20:57:36] <letrec> один мой хороший приятель, крутой C++'ник стебался, что надо стремиться, чтобы программа превратилась в один typdef и её изменение сводилось к выбору аргументов шаблона
[20:57:49] <letrec> мне кажется моноид это из той же оперы
[20:58:01] <letrec> хардкорное задротство
[20:58:23] <letrec> которым можно заниматься, если в команде все молодцы и есть время
[20:58:33] <letrec> что бывает редко
[20:58:38] <gds> один раз определив, использую на списках, массивах, итератах.  как раз недавно был обход списка, а теперь на его месте свёртка на итератах.  пичалька.
[20:59:58] <letrec> ты абстрагировался от контейнера, в моём случает в нём туплы, от них тоже абстрагировался бы?
[21:00:55] <letrec> или это так и есть в случае с моноидом?
[21:04:44] <gds> в случае моноидов -- будет моноид поверх туплов.  при желании его можно либо явно выписать, либо собрать из двух моноидов поверх каждого из компонентов, тривиально.
[21:05:06] <gds> кстати, собственно моноиды не советую, лучше "расширенные моноиды", сам придумал.  показать?
[21:08:47] <letrec> расширенные каким образом? дай хинт
[21:10:40] <gds> зачем хинт, когда есть реализация.  https://bitbucket.org/gds/cadastr/src/a5143d184447/src/monoid.ml
[21:12:16] <letrec> а почему на объектах сделано, а не на модулях?
[21:14:38] <gds> более легковесный синтаксис.  кроме того, во всех применениях за O(1) достаются собственно значения методов, и оверхеды несущественны.
[21:15:20] <letrec> оверхедом будет аллокация объекта для каждого значения?
[21:17:11] <gds> для каждого _какого_ значения?
[21:17:52] <gds> после вызова obj#meth у тебя на руках честная функция, ровно такая же, как после Module.func.
[21:21:23] <letrec> я с объектами в окамле пока плохо знаком, поэтому не уверен, что правильно понимаю как твоим моноидом пользоваться
[21:21:38] <letrec> создаём экземпляр Monoid.t, потом кормим функции из Monoid им вместе с значениями?
[21:21:57] <gds> кстати, мало кто знает (хотя f[x] обязан знать, ну и я), что в случае, когда тайпчекер имеет закрытый/фиксированный объектный тип, он берёт значения не бинарным поиском по хешу метода, а по фиксированному смещению.  то есть, то же, что в записях и fcm.
[21:23:37] <gds> пользоваться -- например, http://paste.in.ua/3754/
[21:25:28] <letrec> а зачем let p = mon#plus?
[21:25:29] <gds> а вот этот самый mon создаём либо через new Monoid.t (и далее расширяем его до ext через new id_extend mon), либо через new Monoid.ext сразу.  Мне для разграничения по типам нужны были два разных типа, потому и "расширение".  Впрочем, это можно исправить.
[21:26:03] <letrec> а модули разве нельзя расширять подобным образом?
[21:26:17] <gds> затем, чтобы взять метод plus : 'a -> 'a -> 'a один раз и его использовать, не узнавая у объекта каждый раз, где у него метод.  Так всяко быстрее.
[21:27:05] <letrec> в чём здесь профит от объектов?
[21:27:06] <gds> модули -- смотря каким образом.  Тут -- можно.  Но мне не нравился синтаксис, и проектировалось это тогда, когда fcm не было (точнее, было в транке).
[21:27:24] ftrvxmtrx вошёл(а) в комнату
[21:27:29] <letrec> а тебе позднее связывание было нужно?
[21:28:02] <gds> было, конечно.  только не вспомню, где именно.  ну, в кадастре было точно, но там неинтересно.
[21:28:14] <gds> когда простую гуйню писал, было нужно.
[21:30:06] <gds> вообще, во всех случаях, когда хер проссыш, как должно всё работать (с учётом будущих изменений), я выбираю полиморфные варианты и объекты.  Но в половине случаев, после того, как задалбывают ошибки полиморфных вариантов (ну и когда я понимаю задачу более полно), я переписываю их в обычные.  С объектами же такого не случалось пока.
[21:32:29] <gds> а ещё вот в окамле есть три частично дублирующие друг друга сущности -- модули, записи и объекты.  можно было бы слить воедино.  вот за это я порицаю инрию.  однако, так сложилось исторически, и сливать -- очень долго и очень геморно.
[21:33:29] <letrec> комменты в revised syntax так же как и в обычном пишутся?
[21:33:36] <gds> да.
[21:35:04] <letrec> ну, они только частично дублируются насколько я понимаю
[21:35:47] <letrec> и заменять объекты записями это как-то совсем по сишному будет
[21:35:55] <letrec> сделай всё сам
[21:38:00] <gds> да, частично.  принцип почти один, но: 1. модули могут объявлять свои типы, в том числе абстрактные, 2. записи имеют фиксированное и быстрое время доступа к полю записи, 3. объекты могут расширяться и типизироваться уточкой.
в итоге вырастает сущность, которая 1. может определять свои локальные типы, 2. позволяет доступ по смещению к полю в случае, когда смещение известно (когда тип закрыт, или когда поле объявлено как "поле записи"), 3. позволяет иметь подтипизацию на некоторых полях (не объявленных как "поле записи").
[21:40:56] <letrec> я так понимаю, что если замапить модули и объекты на Java/C#, то все значения, торчащие из модуля static, а в объектах instance
[21:42:01] <gds> если про мой "проект", то, видимо, да.  но в java/c# я мало разбираюсь, на практике не использовал.
кроме того, надо как-то типы определять.
[21:43:38] <letrec> а объекты это записи с опционально мутабельными полями
[21:43:57] <letrec> и перекрытие это просто мутация полей
[21:44:54] <gds> 1. в записях тоже есть мутабельные поля.  2. там не только мутабельность -- там, собственно, структурная типизация, инициализация, значения (приватные для объекта), виртуальные методы, приватные методы, их смесь.
[21:45:43] <letrec> я рассмотриваю виртуальные методы как мутабельные поля типа функция
[21:46:00] <letrec> отличие вроде в том, что там открытая рекурсия
[21:46:05] <letrec> в объектах
[21:46:52] <letrec> кстати да, чтобы поиметь структурную типизацию их на записях не реализуешь
[21:46:54] <gds> тогда, скорее, там не мутабельные поля, а просто shadowing на уровне полей, т.е. в иммутабельном случае тоже реализуемо, есть же чисто функциональные объекты (кстати, такие и нужны обычно; состояние лучше хранить отдельно, если приемлемо).
[21:47:58] <gds> ну и в объектах есть доступ ко всем методам (а может и к значениям, но вроде нет) классов, от которых наследуешься.  даже с перекрывающимися методами при множественном наследовании можно нормально работать.  только вот ни разу не приходилось.
[21:48:37] <letrec> да, т.е простой мутацией не обойтись - надо где-то хранить родительские значения
[21:49:16] <letrec> вот в модулях перекрытие можно сэмулировать с помощью функторов и мутабельных значений?
[21:51:53] <gds> если явно прописывать "let val1 = F1.val1  let val2 = F2.val2" -- можно и без мутабельности, и тоже будет всё храниться.  Только обычно сильно влом выписывать все значения всех модулей, а как там дела обстоят в случае "include F1  include F2" -- не очень помню.  Вроде последнее перекрывает в значениях, но конфликты с типами (для чего и выдумали "include Fn with type t := s").
[22:00:36] <gds> остоэтосамое всем боян, но вдруг кто не видел: https://www.destroyallsoftware.com/talks/wat
[22:11:27] bobry вошёл(а) в комнату
[22:14:41] Andrey Popp вошёл(а) в комнату
[22:18:32] letrec вышел(а) из комнаты
[23:07:31] komar вышел(а) из комнаты: Replaced by new connection
[23:07:31] komar вошёл(а) в комнату
[23:08:26] bobry вышел(а) из комнаты
[23:08:41] bobry вошёл(а) в комнату
[23:15:39] dzhon вошёл(а) в комнату
[23:17:16] <bobry> gds: глупый вопрос -- ты пишешь код без манаток? в принципе
[23:17:25] <bobry> или "зависит от задачи"?
[23:18:43] shaggie вышел(а) из комнаты
[23:25:50] <gds> bobry: зависит от задачи, конечно.  Но в случае "тяжелой артиллерии" предпочитаю манатки сразу, для ввода-вывода и для обработки ошибок, и нередко это одна и та же манатка.
[23:26:18] <bobry> gds: манатки для освобождения ресурсов или что?
[23:27:24] <gds> говорю же "для ввода-вывода и для обработки ошибок".
освобождение ресурсов -- with-идиома обычно.  если она расширяется на случай манаток, то это не так уж и плохо.
[23:27:43] <bobry> погоди, в чем тогда бонус манаток для io?
[23:28:07] <gds> возможность использовать как окамловский ввод-вывод, так и lwt, например.
[23:28:20] <bobry> т.е. абстракция?
[23:28:42] <gds> вроде как так.
[23:29:21] <bobry> как то с трудом представляю когда может потребоваться смешивать lwt io и обычный
[23:29:29] <bobry> или переключаться с одного на другой
[23:29:42] <gds> смешивать -- не нужно, переключаться -- нужно (мне).
[23:30:14] <gds> точнее, не столько переключаться, сколько реюзать код между разными проектами, когда они "под разное" делаются.
[23:30:22] <bobry> ах, теперь ясно
[23:34:00] <gds> ну и обработка ошибок -- при использовании Res имеем, что исключения не могут просочиться, нарушив control flow.  (точнее, могут, но по ошибке, а эти ошибки исключать несложно.)
кроме того, итераты используют монады, и там тоже, хоть Identity, но предоставь.
а другие монады, наподобие List, я использовал мало.
вот точу зуб на Cont, она, по слухам, хорошо заменяет with-идиому.  Но до этого дойти умом надо ещё.
[23:35:56] <gds> а вот с монадными edsl у меня не срослось как-то.  тупой, наверное.
[23:36:10] <bobry> шо за монадные edsl?
[23:36:23] <bobry> а ты без do их используешь? все байнды явные?
[23:37:02] <gds> это такой хак в х-е, который использует как раз do-нотацию для удобства.
да, использую без do, ты видел в барбре.  впрочем, это не напрягает.
[23:37:08] komar тоже не сросся.
[23:37:32] <gds> komar: велкам в клуб тупых.
[23:38:23] <bobry> gds: link?
[23:38:26] <komar> Это они понапридумают себе хреноты, никакого однообразия.
[23:38:42] <bobry> меня вот явные байнды напрягают, видимо с непривычки ..
[23:38:45] <gds> какой линк?  на монадные едсл -- нет линка.
[23:38:48] <bobry> komar: кто "они"?
[23:38:52] ftrvxmtrx вышел(а) из комнаты
[23:39:03] <komar> bobry: те, кто не в клубе.
[23:39:05] ftrvxmtrx вошёл(а) в комнату
[23:43:08] ftrvxmtrx вышел(а) из комнаты
Powered by ejabberd Powered by Erlang Valid XHTML 1.0 Transitional Valid CSS!