-- | -- Module : Control.Monad.Levels -- Copyright : Sebastian Fischer -- License : PublicDomain -- -- Maintainer : Sebastian Fischer (sebf@informatik.uni-kiel.de) -- Stability : experimental -- Portability : portable -- -- This library provides an implementation of the MonadPlus type -- class that enumerates the levels of the search space and allows to -- implement breadth-first search. -- -- The implementation is inspired by Mike Spivey and Silvija Seres: -- cf. Chapter 9 of the book 'The Fun of Programming'. -- -- Warning: @Levels@ is only a monad when the results of the -- enumeration functions are interpreted as a multiset, i.e., a valid -- transformation according to the monad laws may change the order of -- the results. module Control.Monad.Levels ( Levels, levels, breadthFirstSearch, DepthBound, iterLevels, iterativeDeepening, diagonals ) where import Control.Monad -- | -- Non-Deterministic computations of type @Levels a@ can be searched -- level-wise. newtype Levels a = Levels { -- | -- The function @levels@ yields the results of a non-deterministic -- computation grouped in levels. levels :: [[a]] } -- | -- The function @breadthFirstSearch@ enumerates the results of a -- non-deterministic computation in breadth-first order. breadthFirstSearch :: Levels a -> [a] breadthFirstSearch = concat . levels instance Monad Levels where return x = Levels [[x]] Levels x >>= f = Levels (x `bind` (levels . f)) fail _ = Levels [] bind :: [[a]] -> (a -> [[b]]) -> [[b]] bind x f = map concat (diagonals (map (foldr zipConc [] . map f) x)) instance MonadPlus Levels where mzero = Levels [] Levels xs `mplus` Levels ys = Levels ([] : zipConc xs ys) -- | -- The type @DepthBound@ represents computations with a bounded -- depth. It's monad instances implements iterative deepening. newtype DepthBound a = DepthBound { (!) :: Int -> [(a,Int)] } instance Monad DepthBound where return x = DepthBound (\d -> [(x,d)]) a >>= f = DepthBound (\d -> [ y | (x,d') <- a!d, y <- f x!d' ]) fail _ = DepthBound (const []) instance MonadPlus DepthBound where mzero = DepthBound (const []) a `mplus` b = DepthBound (\d -> do guard (d>0) let d' = d-1 (a!d') `mplus` (b!d')) -- | -- The function @iterLevels@ computes the levels of a depth bound -- computation using iterative deepening. iterLevels :: DepthBound a -> Levels a iterLevels a = Levels [[ x | (x,0) <- a!d ] | d <- [0..]] -- | -- The function @iterativeDeepening@ enumerates the results of a -- non-deterministic computations using iterative deepening. iterativeDeepening :: DepthBound a -> [a] iterativeDeepening = concat . levels . iterLevels -- | -- The function @diagonals@ enumarates the entries of a matrix -- diagonally. The matrix may contain an infinite number of infinite -- rows. diagonals :: [[a]] -> [[a]] diagonals [] = [] diagonals (xs:xss) = zipConc [[x] | x <- xs] ([] : diagonals xss) zipConc :: [[a]] -> [[a]] -> [[a]] zipConc [] yss = yss zipConc xss [] = xss zipConc (xs:xss) (ys:yss) = (xs++ys) : zipConc xss yss