хвостато-рекурсивные функции в монадах
Jan. 24th, 2007 07:54 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Когда мы пишем монадическую функцию с хвостовой рекурсией, то явно эта функция не хвостато-рекурсивная:
Например, эта функция выглядит как
Я здесь хвостатости не вижу. Я предполагаю, что реализация
Чтобы было ясно, что я имею в виду:
Откуда следует, что
Кто подскажет?
loop = do
cmd <- getLine
if (cmd == ":q")
then return ()
else loop
Например, эта функция выглядит как
loop = getLine >>= \cmd ->
if (cmd == ":q")
then return ()
else loop
Я здесь хвостатости не вижу. Я предполагаю, что реализация
(>>=)
такова, что bind
переводит запись c foo = m >>= foo
в хвостовую рекурсию. Чтобы было ясно, что я имею в виду:
instance Monad Identity where
return a = Identity a
m >>= k = k (runIdentity m)
Откуда следует, что
f = m >>= f
преобразуется в f = f (runIndentity m)
. Но, с другой стороны, это только в случае инлайна будет возможна такая оптимизация. И фиг знает, что там с другими монадами. Полагаю, что их тоже можно развернуть в хвостатую запись. Может быть кто нибудь поможет с объяснением или ссылкой - почему так? Может быть на это влияет семантика монад, в частности то, что в m >>= f
f
не будет выполнено до тех пор, пока не будет выполнен m
.Кто подскажет?
no subject
Date: 2007-01-24 04:59 pm (UTC)no subject
Date: 2007-01-24 05:05 pm (UTC)Возможен тут меморилик? Нет? Почему нет?
no subject
Date: 2007-01-24 05:16 pm (UTC)no subject
Date: 2007-01-24 05:26 pm (UTC)У меня монада была реализована как замыкание. Насколько я помню IO реализованна так же.
no subject
Date: 2007-01-24 08:09 pm (UTC)no subject
Date: 2007-01-25 12:32 am (UTC)Хорошо, не поленился добавил лени :-) Работает, хвала всевышнему.
теперь получается что то вроде (словами Хаскеля)
Ну, это больше похоже на хвостовую рекурсию. Особенно в Haskell это выльется loop world = let .. in loop next_world.
С IO разобрался, хорошо. Но неужели мне так со всеми монадами надо разбираться, чтобы понять? Должно же быть где то теоретическое обоснование! Какое то простое объяснение, следующее из закона монад или ещё что...
no subject
Date: 2007-01-25 06:54 am (UTC)leak = do {a <- [1,2,3] ; leak }
Не проверял. Но думаю, 100% будет утечка.
no subject
Date: 2007-01-25 07:15 am (UTC)leak !! 1000 замерает. На Сtrl-C не реагирует.
А вот код leak arg = do { a <- [1,2,3]; leak a }
как раз ведет себя как и ожидалось:
stack overflow на leak 1 !! 1000
no subject
Date: 2007-01-25 10:57 am (UTC)Надо будет поглядеть насчёт списков внимательнее, а то я не пойму ни фига - с чего это leak без аргументов не течёт
no subject
Date: 2007-01-25 12:15 pm (UTC)Может deadlock какой случился с ghci? :)
no subject
Date: 2007-01-25 12:38 pm (UTC)это после инлайнинга. Это выражение тоже ничего не делает, когда запускаю leak !! 1000
no subject
Date: 2007-01-24 05:03 pm (UTC)Поэтому проблем не возникает. Обычно. ;)
no subject
Date: 2007-01-24 05:06 pm (UTC)no subject
Date: 2007-01-24 05:30 pm (UTC)no subject
Date: 2007-01-24 05:20 pm (UTC)no subject
Date: 2007-01-24 05:31 pm (UTC)no subject
Date: 2007-01-25 12:30 am (UTC)(Кстати переписал на схему)
no subject
Date: 2007-01-25 10:48 am (UTC)Это выяснилось не так давно в нашем проекте.
no subject
Date: 2007-01-25 10:55 am (UTC)no subject
Date: 2007-01-25 11:59 am (UTC)При этом все количества вызовов в программе по профайлеру линейно от количества тиков, которые надо просимулировать.
У меня получилась сложность вроде такой: время симуляции в секундах T=2e-7*N2+0.00015*N+5. N - количество эмулируемых тиков. T(1000) = 5.35, а вот T(100000) = 2020, 34 минуты.
Неприятно, но жить можно и времени заниматься уже нет. :(
no subject
Date: 2007-01-25 07:43 am (UTC)Я добавил там кое-что по мотивам этого треда. ;)
no subject
Date: 2007-01-25 10:57 am (UTC)