Предположим, кто-то создает программу для игры в шахматы или решает судоку. В такой программе имеет смысл иметь древовидную структуру, представляющую игровые состояния.
Это дерево было бы очень большим, "практически бесконечным". Что само по себе не является проблемой, поскольку Haskell поддерживает бесконечные структуры данных.
Знакомый пример бесконечной структуры данных:
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Узлы выделяются только при первом использовании, поэтому список занимает ограниченную память. Можно также перебирать бесконечный список, если они не сохраняют ссылки на его заголовок, что позволяет сборщику мусора собирать его части, которые больше не нужны.
Вернемся к примеру с деревом - предположим, что кто-то выполняет итерацию по дереву, итерированные узлы дерева могут быть не освобождены, если корень дерева все еще нужен (например, при итеративном углублении поиска дерево будет повторяться более чем в несколько раз, и поэтому корень должен быть сохранен).
Одним из возможных решений этой проблемы, о котором я подумал, является использование «unmemo-monad».
Я попытаюсь продемонстрировать, что эта монада должна делать, используя монадические списки:
import Control.Monad.ListT (ListT) -- cabal install List
import Data.Copointed -- cabal install pointed
import Data.List.Class
import Prelude hiding (enumFromTo)
nums :: ListT Unmemo Int -- What is Unmemo?
nums = enumFromTo 0 1000000
main = print $ div (copoint (foldlL (+) 0 nums)) (copoint (lengthL nums))
Используя nums :: [Int]
, программе потребовалось бы много памяти, так как ссылка на nums
необходима для lengthL nums
, пока она повторяется по foldlL (+) 0 nums
.
Цель Unmemo
- сделать так, чтобы среда выполнения не поддерживала повторение узлов.
Я попытался использовать ((->) ())
в качестве Unmemo
, но он дает те же результаты, что и nums :: [Int]
- программа использует много памяти, что очевидно, если запустить ее с +RTS -s
.
Есть ли способ реализовать Unmemo
, который делает то, что я хочу?