-- |-- 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'. The-- implementation of iterative deepening depth-first is, however,-- significantly simpler thanks to the use of a continuation monad.-- -- 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.moduleControl.Monad.Levels(bfs,idfs,idfsBy)whereimportData.MonoidimportData.FMList-- | The function @bfs@ enumerates the results of a-- non-deterministic computation in breadth-first order.bfs::FMLista->[a]bfsa=runLevels(unFMayield)whereyieldx=Levels[singletonx]-- Non-Deterministic computations of type @Levels a@ can be searched-- level-wise.newtypeLevelsa=Levels{levels::[FMLista]}-- Concatenates levels amd yields result as list. runLevels::Levelsa->[a]runLevels=toList.foldrappendempty.levelsinstanceMonoid(Levelsa)wheremempty=Levels[]a`mappend`b=Levels(empty:merge(levelsa)(levelsb))-- like 'zipWith append' without cutting the longer listmerge::[FMLista]->[FMLista]->[FMLista]merge[]ys=ysmergexs[]=xsmerge(x:xs)(y:ys)=appendxy:mergexsys-- | The function @idfs@ computes the levels of a depth bound-- computation using iterative deepening depth-first search. Unlike-- breadth-first search it runs in constant space but usually takes a-- bit longer, depending on how the depth limit is increased. Don't-- use this algorithm if you know that there is only a finite number-- of results because it will continue trying larger depth limits-- without recognizing that there are no more solutions.idfs::FMLista->[a]idfs=idfsBy100-- | The function @idfsBy@ computes the levels of a depth bound-- computation using iterative deepening depth-first search-- incrementing the depth limit between searches using the given-- number of steps.idfsBy::Int->FMLista->[a]idfsByna=toList$foldrappendempty[unFMayield!d|d<-[0,n..]]whereyieldx=DepthBound(\d->ifd<nthensingletonxelseempty)-- The type @DepthBound@ represents computations with a bounded depth-- to iterative deepening search.newtypeDepthBounda=DepthBound{(!)::Int->FMLista}instanceMonoid(DepthBounda)wheremempty=DepthBound(constempty)a`mappend`b=DepthBound(\d->ifd==0thenemptyelseappend(a!(d-1))(b!(d-1)))