Set
, аналогично []
имеет совершенно определенные монадические операции. Проблема в том, что они требуют, чтобы значения удовлетворяли условию Ord
, и поэтому невозможно определить return
и >>=
без каких-либо ограничений. Эта же проблема применяется ко многим другим структурам данных, которые требуют каких-либо ограничений на возможные значения.
Стандартный трюк (предложенный мне в статье haskell-cafe) заключается в том, чтобы обернуть Set
в монаду продолжения. ContT
не имеет значения, имеет ли функтор базового типа какие-либо ограничения. Ограничения становятся необходимыми только при переносе/распаковке Set
в/из продолжений:
import Control.Monad.Cont
import Data.Foldable (foldrM)
import Data.Set
setReturn :: a -> Set a
setReturn = singleton
setBind :: (Ord b) => Set a -> (a -> Set b) -> Set b
setBind set f = foldl' (\s -> union s . f) empty set
type SetM r a = ContT r Set a
fromSet :: (Ord r) => Set a -> SetM r a
fromSet = ContT . setBind
toSet :: SetM r r -> Set r
toSet c = runContT c setReturn
Это работает по мере необходимости. Например, мы можем моделировать недетерминированную функцию, которая либо увеличивает свой аргумент на 1, либо оставляет его неповрежденным:
step :: (Ord r) => Int -> SetM r Int
step i = fromSet $ fromList [i, i + 1]
-- repeated application of step:
stepN :: Int -> Int -> Set Int
stepN times start = toSet $ foldrM ($) start (replicate times step)
Действительно, stepN 5 0
дает fromList [0,1,2,3,4,5]
. Если бы мы использовали вместо монады []
, мы получили бы
[0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5]
вместо.
Проблема эффективность. Если мы назовем stepN 20 0
, вывод займет несколько секунд, а stepN 30 0
не закончится в течение разумного промежутка времени. Оказывается, что все операции Set.union
выполняются в конце, а не выполняют их после каждого монадического вычисления. Результат состоит в том, что экспоненциально много Set
построены и union
ed только в конце, что неприемлемо для большинства задач.
Есть ли способ обойти это, чтобы сделать эту конструкцию эффективной? Я пробовал, но безуспешно.
(Я даже подозреваю, что могут существовать некоторые теоретические пределы, вытекающие из изоморфизма Карри-Говарда и теоремы Гливенко. Теорема Гливенко гласит, что для любой пропозициональной тавтологии φ формула ¬¬φ может быть доказана в интуиционистской логике. Однако я подозреваю, что длина доказательства (в нормальной форме) может быть экспоненциально длинной. Поэтому, возможно, могут быть случаи, когда перенос вычисления в монаду продолжения сделает ее экспоненциально длиннее?)