Как бы вы реализовали монаду обратного состояния в OCaml? (Поскольку он сильно зависит от лени, я думаю, нужно использовать модуль Lazy из стандартной библиотеки).
Монада обратного состояния в OCaml
comment
Как насчет монады Tardis, слишком? Отлично подходит для подсчета очков боулинга, среди прочего .
- person Boyd Stephen Smith Jr.   schedule 25.07.2014
comment
@BoydStephenSmithJr.: Вы задаете еще вопрос?
- person Bob   schedule 25.07.2014
comment
Я полагаю, да. Но я подожду ответа на этот вопрос, прежде чем опубликовать свой.
- person Boyd Stephen Smith Jr.   schedule 25.07.2014
comment
@ Боб, что ты пробовал? Я могу сказать вам, что реализация этого с помощью модуля Lazy работает почти так, как вы ожидаете. Вам нужно только подтверждение существования или у вас есть более конкретный вопрос?
- person Lambdageek   schedule 25.07.2014
comment
@Lambdageek: мой вопрос: как это сделать без зацикливания в OCaml? Куда бы я ни положил лень, я всегда получаю зацикливание рекурсии. Было бы здорово, если бы вы написали ответ.
- person Bob   schedule 25.07.2014
Ответы (1)
Я выложил суть решения.
Сложный момент:
type 's l = 's Lazy.t
type ('a, 's) st = 's -> ('a * 's l)
let bind (mx : ('a, 's) st) (f : ('a -> ('b, 's) st)) (s : 's l) : ('b * 's l) =
(* conceptually we want
let rec (lazy (y, s'')) = lazy (mx s')
and (lazy (z, s')) = lazy (f y s)
in (force z, s'')
but that's not legal Caml.
So instead we get back lazy pairs of type ('a * 's l) l and we
lazily project out the pieces that we need.
*)
let rec ys'' = lazy (mx (LazyUtils.join (LazyUtils.snd zs')))
and (zs' : ('b * 's l) l) = lazy (f (Lazy.force (LazyUtils.fst ys'')) s)
in (Lazy.force (LazyUtils.fst zs'), LazyUtils.join (LazyUtils.snd ys''))
Как я уже упоминал в комментарии, несколько хитрость заключается в том, что вы не хотите случайно принудительно вычислить состояние слишком рано. К сожалению, чтобы получить правильную взаимную рекурсию, вы также вынуждены временно сделать ответы вычислений (которые текут вперед) ленивыми. Итак, основные правила игры таковы:
- Делайте то, что типы говорят вам делать.
- Никогда не форсируйте состояние, кроме как в конструкции
lazy e
.
В частности, LazyUtils.join : 'a Lazy.t Lazy.t -> 'a Lazy.t
не может быть:
let join xll = Lazy.force xll
Потому что это заставит внешний преобразователь слишком рано. Вместо этого должно быть:
let join xll = lazy (Lazy.force (Lazy.force xll))
Что выглядит как заикание, но на самом деле корректно задерживает все вычисления.
person
Lambdageek
schedule
24.07.2014
Большое спасибо за этот отличный ответ. Я смог заново открыть для себя ваш ответ после изучения ваших уловок. Затем я провел остаток дня, пытаясь обобщить это на случай монады обратного состояния transformer. Но я застрял: я не могу определить привязку. Единственное решение, которое я могу смутно представить, будет использовать mfix монады в параметре, но это само по себе проблематично определить, потому что это приводит к зацикливанию рекурсии. Вот почему я задаю этот другой вопрос. Есть идеи?
- person Bob; 25.07.2014