Home
Objective Caml
ocaml@conference.jabber.ru
Пятница, 19 февраля 2010< ^ >
f[x] установил(а) тему: Камль -- http://caml.inria.fr | Логи -- http://chatlogs.jabber.ru/ocaml@conference.jabber.ru/ | Верблюды грязи не боятся! | release crap | voice по запросу | ocaml мёртв, move on
Конфигурация комнаты
Участники комнаты

GMT+3
[00:09:06] digital_curse вышел(а) из комнаты
[00:11:06] gds вышел(а) из комнаты: Replaced by new connection
[00:11:07] gds вошёл(а) в комнату
[00:38:19] ermine вышел(а) из комнаты
[00:44:51] gds вышел(а) из комнаты
[00:55:06] iNode вышел(а) из комнаты
[01:30:23] sceptic вышел(а) из комнаты: Replaced by new connection
[01:30:29] sceptic вошёл(а) в комнату
[01:51:29] sceptic вышел(а) из комнаты
[01:51:59] sceptic вошёл(а) в комнату
[02:25:16] sceptic вышел(а) из комнаты
[02:48:14] olegfink вышел(а) из комнаты
[02:48:34] Typhon вышел(а) из комнаты
[02:57:37] daapp вошёл(а) в комнату
[07:16:03] ermine вошёл(а) в комнату
[07:27:12] ermine вышел(а) из комнаты
[07:27:15] ermine вошёл(а) в комнату
[08:17:22] iNode вошёл(а) в комнату
[09:02:56] gds вошёл(а) в комнату
[09:13:28] Sergey Plaksin вошёл(а) в комнату
[09:13:40] Sergey Plaksin вышел(а) из комнаты
[10:51:05] Sergey Plaksin вошёл(а) в комнату
[11:10:31] sceptic вошёл(а) в комнату
[11:11:18] sceptic вышел(а) из комнаты
[11:11:22] sceptic вошёл(а) в комнату
[11:33:54] <f[x]> реквестирую флешмоб в PR#4982. всё никак не доходил чтобы разобраться чего это у меня бектрейсы какие-то маловменяемые. mottl гуд.
[11:37:36] <gds> done
[11:37:51] <gds> monitored, в смысле.
[12:29:00] <gds> оффтопик, но тут минимум два человека щупали coq, который к окамлу вполне относится, поэтому http://xkcd.com/704/
[12:32:39] Typhon вошёл(а) в комнату
[12:35:22] <f[x]> :)
[13:06:39] <Typhon> Привет всем! нужны подсказки, мнения и советы. Дано:
let write = prepare >> render (Config.option "template") >> write_buff (Config.option "conf"), где Config.option вытягивает опции из Hashtbl. данные в таблицу попадают из файла после инициализации конфига, которая проводится в "main'е". write находится на верхнем уровне и потому ожидаемо выполняется и программа падает, т.к. не находит нужную опцию. это решается оборачиванием функции в лямбда абстракцию (не ошибся? :)) : let write fun n -> prepare n |> render  (Config.option "template") |> write_buff (Config.option "conf"). Интересует: есть ли еще способы гарантировать выполнение write после инициализации конфигов и как вы конфигурацию храните/используете?
[13:13:33] <gds> самое простое -- сделать так, чтобы конфиг заполнялся до того места, как в области видимости окажутся функции, берущие из него значения опций.
[13:17:49] <gds> то есть, читать конфиг в модуле Config.
если же не получится (а бывает так, что не получается), можно читать конфиг в нужном месте.  Да хоть в main.  Например, let config = Config.read_from_file "..." in prepare >> render (Config.option config "template") >> ... или let config = Config.get () in ... (то есть, зависимость по данным: без создания значения config операции чтения не вызываются).  Можно ещё завернуть в ленивое значение и читать по нужде (но не советую).
[13:21:54] <gds> а ещё есть такой стиль: не давать наружу полуготовых структур данных, если это допустимо.  Если даётся хештаблица со значениями конфига, там же её и заполнять:
let h = Hashtbl.create .. in ( read_config_to h ; h )
если revised syntax и извращаться слегка, то можно
let h = Hashtbl.create .. in h where () = read_config_to h
[13:31:25] <Typhon> у меня в main init_config вызывается для инициализации, а write находится в отдельном модуле. ну и вообще обращение к Config.option еще из нескольких модулей обращение происходит (но там не на верхнем уровне и все ок).
в самом модуле Config не хочется читать, потому что я daemonize вызываю. И, насколько я понимаю, если конфиг читается до демонизации, то он будет прочитан по сути два раза (это так, или я ошибаюсь?). поэтому я инициализацию конфигов делаю после: let () = daemonize () in let () = Config.init_config flnm. Хотя последний способ идеологически нравится :)
[13:32:34] <f[x]> с чего это два раза?
[13:32:40] <gds> чтение конфига -- дёшево, в среднем.
демонизация -- fork, в конце концов?  если да, то один раз.
[13:34:28] <f[x]> читать конфиг/комстроку на верхнем уровне - самое простое и удобное т.к. камль гарантирует что все модули которые используют config будут проинициализированы после него
[13:36:04] <gds> вроде бы, кроме случаев module rec Config = .. and Module_that_uses_config = .., но это можно не учитывать в данной задаче.
[13:37:36] <f[x]> угу
[13:38:42] <f[x]> и кстати что это за write на верхнем уровне - почему не в main?
[14:11:12] <Typhon> f[x]: это в модуле Template функция (одна из серии write_*), которая генерит нужный файл по шаблону, поэтому ей не место в main (она по запросу вызывается). с демонизацией я значит протупил, надо исправиться :)
[14:11:44] daapp вышел(а) из комнаты
[14:15:16] <gds> тогда вполне разумно поместить обращения к конфигу за лямбду.  в идеале -- туда, где производятся другие сайд-эффекты.
[14:42:16] ygrek вышел(а) из комнаты
[14:53:05] <Typhon> кстати, еще вчера наткнулся (вполне очевидно тоже, но на всякий случай): имя такие with_file (http://paste.in.ua/351/) и такой код: let s = with_file source Stream.of_channel in Stream.next s -- мы получим Sys_error "Bad file descriptor", ибо Stream лениво читает данные, а файлик уже закрыт
[14:56:09] <gds> о да, есть такое.  Как в общем случае защититься от подобного -- не знаю.  Долепить можно как-то типа: with_file source (fun ch -> with_stream (Stream.of_channel ch) (fun s -> ...))
[14:56:29] <gds> точнее, with_stream нафиг не нужен.
[14:56:46] <gds> with_file source (fun ch -> let s = Stream.of_channel s in Stream.next s)
[14:59:57] <Typhon> я композицю делаю из функций, который работать должны с потоком: let parse_file = flip with_file_in (Stream.of_channel >> make_lexer ["="; ";"] >> parse_conf)
[15:03:02] <gds> при подобной композиции трудно проследить, где заканчивается область кода, где файл открыт, поэтому лично я тут не делал бы композицию.
[15:12:50] <Typhon> а почему трудно, можешь объяснить? вроде код "рабочий" в скобочках тоже
[15:19:02] <gds> а, если код тоже в скобочках with_file_in (...), то всё нормально.  Потому что в примере с let s = with_file_in ... (...) in Stream.next s ситуация была другая.
[15:28:56] <Typhon> gds: а вон я с композицией кинул: let parse_file = flip with_file_in (Stream.of_channel >> make_lexer ["="; ";"] >> parse_conf) -- по-моему, ничо так :)
[15:30:49] <gds> прилично.  но я бы имя файла всё-таки вытащил явным образом, как-то так:
let parse_file filename = with_file_in filename (Stream.of_channel >> make_lexer ["="; ";"] >> parse_conf)
лично мне так легче проследить, какие аргументы принимают функции parse_file и with_file_in.
[15:32:53] <Typhon> да, наверное, этот их "point-free style" по началу клевый, но потом как-то бесит иногда.
[15:35:37] <gds> вообще, почти не видел примеров, где flip и подобные функции, переставляющие аргументы, чем-то сильно упрощали код.  исключения -- инфиксные композиции/пайпы, но и там не всегда код получается сильно лучше.  да и вообще, чувство прекрасного у каждого своё.  я вот нагло сообщаю о том, какое оно у меня.
[16:03:01] sceptic вышел(а) из комнаты
[16:06:56] sceptic вошёл(а) в комнату
[16:26:36] <gds> понятно, почему
let () = (fun d -> (d 0; d "")) ignore;;
не типизируется: унификация делает тип d фиксированным.  Но не ясно, почему тип "шарится", и это не типизируется тоже:
let () = (fun d -> let d1 x = d x and d2 x = d x in (d1 0; d2 "")) ignore;;
есть идеи, зачем/почему такое?
[16:42:46] <f[x]> по-моему всё логично.. у d будет обычный полиморфный тип
[16:44:56] <f[x]> наверное rank1 полиморфизм, квантор общности влево до упора - hence результат
[16:48:00] <f[x]> если функция d была бы определена снаружи - у неё был бы свой квантор общности
# let f () = (ignore,ignore);;                                                    
val f : unit -> ('a -> unit) * ('b -> unit) = <fun>
# let f (ignore :'a -> unit) = (ignore,ignore);;                                  
val f : ('a -> unit) -> ('a -> unit) * ('a -> unit) = <fun>
# let f ignore = (ignore,ignore);;                                                
val f : 'a -> 'a * 'a = <fun>
[16:48:06] <gds> по идее -- должен был быть, но нет:
# let () = (fun d -> let d1 x = d x and d2 x = d x in (d1 0; d2 "")) ignore;;
Characters 62-64:
  let () = (fun d -> let d1 x = d x and d2 x = d x in (d1 0; d2 "")) ignore;;
                                                                ^^
Error: This expression has type string but an expression was expected of type
         int
(подчёркнуты две кавычки)
если оно выводит тип для let x = a in b классическим методом вида "узнаем тип a, присвоим его x, протипизируем b согласно типу x", то оно по идее не должно было мономорфизировать тип d при типизации "d1 x".
тёмное дело, имхо.  или где-то что-то явно упустил?
про rank1 -- не понятно.  тот же вариант, но с let d = ignore in ... конечно же прокатывает.
[16:49:38] <gds> твои примеры понял, там всё логично и соответствует интуиции.
[16:56:07] <f[x]> твой пример идентичен.
fun d -> .. === forall 'a. 'a -> ..
fun d -> let g x = d x in g === forall 'a 'b. 'a -> 'b
fun d -> let g x = d x and h x = d x in (g,h) === forall 'a 'b. ('a -> 'b) * ('a -> 'b)
[16:56:24] <f[x]> то есть полиморфные переменные вынесены влево
[16:57:40] <f[x]> неважно сколько let'ов ты запихнёшь внутрь - остаётся условие(constraint) на тип d - и оно ограничивает типы всего внутри что использует d
[16:57:43] <f[x]> я так понимаю
[17:00:39] <gds> есть вероятность, что оно сначала типизирует (fun d -> ...), выделяя фиксированный тип для d (d : t), затем при типизации let d1 x = d x and d2 x = d x становится ясно, что t = t1 -> t2, d1 : t1 -> t2, d : t1 -> t2, затем при использовании d1 0 становится ясно, что t1 = int, а при типизации d2 "" становится ясно, что t1 = string.  то есть, тип "шарится" между разными привязками (одинаковый, будь то d, d1 или d2).
твоё объяснение, как я понял уже, об этом же говорит.
так, этот момент я прояснил.  интересно теперь, зачем же понадобилось шарить типы, когда можно было бы в каждом месте вводить новые типовые переменные, и уточнять их (доводить до конкретных типов) только там, где нужно.
[17:01:37] <f[x]> да
[17:03:08] <f[x]> наверное вывод тогда undecidable
[17:17:51] Typhon вышел(а) из комнаты
[17:18:41] Typhon вошёл(а) в комнату
[17:24:48] gds вышел(а) из комнаты
[18:05:08] iNode вышел(а) из комнаты
[19:14:07] Sergey Plaksin вышел(а) из комнаты
[19:18:16] Typhon вышел(а) из комнаты
[19:31:22] <f[x]> module type S = sig type t val f : t -> t end
module type S' = S with type t := int
module type S = sig type 'a t val map : ('a -> 'b) -> 'a t -> 'b t end
module type S1 = S with type t := list
module type S2 = sig
  type 'a dict = (string * 'a) list
  include S with type t := dict
end
[19:33:46] <f[x]> бранч sigsubst
[19:35:08] <f[x]> кто помнится недавно хотел параметризированные сигнатуры? получайте, как по заказу.
[19:41:09] digital_curse вошёл(а) в комнату
[20:24:38] f[x] вышел(а) из комнаты
[21:14:55] sceptic вышел(а) из комнаты
[21:21:01] sceptic вошёл(а) в комнату
[22:10:59] iNode вошёл(а) в комнату
[23:58:27] Typhon вошёл(а) в комнату
Powered by ejabberd Powered by Erlang Valid XHTML 1.0 Transitional Valid CSS!