Set
, как и []
, имеет прекрасно определенные монадические операции. Проблема в том, что они требуют, чтобы значения удовлетворяли ограничению Ord
, поэтому невозможно определить return
и >>=
без каких-либо ограничений. Та же проблема относится ко многим другим структурам данных, которые требуют определенных ограничений на возможные значения.
Стандартный трюк (предложенный мне в сообщении о haskell-cafe) заключается в следующем: оберните Set
в монаду продолжения. ContT
не волнует, имеет ли функтор базового типа какие-либо ограничения. Ограничения становятся необходимыми только при переносе / разворачивании Set
s в / из продолжений:
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
отображаются только в конце, что неприемлемо для большинства задач.
Есть ли способ сделать эту конструкцию эффективной? Я пробовал, но безуспешно.
(Я даже подозреваю, что могут быть какие-то теоретические ограничения, вытекающие из изоморфизма Карри-Ховарда и теоремы Гливенко Теорема Гливенко утверждает, что для любой пропозициональной тавтологии φ формула ¬¬φ может быть доказана в интуиционистской логике. Однако я подозреваю, что длина доказательства (в нормальной форме ) может быть экспоненциально длинным. Так что, возможно, могут быть случаи, когда перенос вычисления в монаду продолжения сделает его экспоненциально длиннее?)
Monad
экземпляра дляSet
, если нет также эффективногоFunctor
экземпляра. И мне трудно понять, как можно получить эффективныйfmap
заSet
. Существующийmap
дляSet
- это n * log n.Set
реализовано в виде строгих деревьев, поэтому лень вам тоже не поможет. - person Luis Casillas   schedule 30.08.2012Ord
или дажеEq
. - person PyRulez   schedule 28.11.2017