Problem with backtracking monad transformer
Guest, Simon
simon.guest@roke.co.uk
Thu, 30 Jan 2003 13:55:50 -0000
This is a multi-part message in MIME format.
--------------InterScan_NT_MIME_Boundary
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
I'm trying to make a backtracking state monad using Ralf Hinze's
backtracking monad transformer. My problem is that it won't backtrack
very far.
Suppose I try ( a >> b ) `mplus` c.
If b fails, it should try c, but it doesn't rewind past a.
My sample code is below.
GHCI> c [0,1] match_1 -- (1 or 0) then 1, OK
GHCI> c [1,0] match_2 -- (1 then 0) or (1,1), OK
GHCI> c [1,1] match_2 -- (1 then 0) or (1,1), fails
What have I misunderstood?
cheers,
Simon
(A disclaimer in an attachment? - it wasn't my idea.)
-- backtracking state monad
-- requires -fglasgow-exts
import qualified Monad as M
import qualified Control.Monad.Trans as MT
-- turn tracing on and off by uncommenting just one of the following =
lines
import Debug.Trace( trace )
--trace s x =3D x
--
-- Ralf Hinze's efficient backtracking monad transformer
--
newtype BACKTR m a
=3D BACKTR { mkBACKTR :: (forall b. (a -> m b -> m b) -> m b -> m b) =
}
instance (Monad m) =3D> Monad (BACKTR m) where
return a =3D BACKTR (\c -> c a)
m >>=3D k =3D BACKTR (\c -> mkBACKTR m (\a -> mkBACKTR (k a) c))
-- We don't use a Backtr class, but do it with the MonadPlus class,
-- mzero is false (fail),
-- mplus is =A6 (orelse)
instance (Monad m) =3D> M.MonadPlus (BACKTR m) where
mzero =3D BACKTR (\c -> id)
m1 `mplus` m2 =3D BACKTR (\c -> mkBACKTR m1 c . mkBACKTR m2 c)
-- standard MonadTrans class has lift for promote, and doesn't have =
observe
instance MT.MonadTrans BACKTR where
lift m =3D BACKTR (\c f -> m >>=3D \a -> c a f)
observe :: (Monad m) =3D> BACKTR m a -> m a
observe m =3D mkBACKTR m (\a f -> return a) (fail "false")
--
-- State Monad
--
data SM st a =3D SM (st -> (a,st)) -- The monadic type
instance Monad (SM st) where
-- defines state propagation
SM c1 >>=3D fc2 =3D SM (\s0 -> let (r,s1) =3D c1 s0
SM c2 =3D fc2 r in
c2 s1)
return k =3D SM (\s -> (k,s))
-- extracts the state from the monad
readSM :: SM st st
readSM =3D SM (\s -> (s,s))
-- updates the state of the monad
updateSM :: (st -> st) -> SM st () -- alters the state
updateSM f =3D SM (\s -> ((), f s))
-- run a computation in the SM monad
runSM :: st -> SM st a -> (a,st)
runSM s0 (SM c) =3D c s0
-- backtracking state monad
--
type NDSM st a =3D BACKTR (SM st) a
readNDSM :: NDSM st st
readNDSM =3D MT.lift readSM
updateNDSM :: (st -> st) -> NDSM st ()
updateNDSM f =3D MT.lift (updateSM f)
--run a computation in the NDSM monad
runNDSM :: st -> NDSM st a -> (a,st)
runNDSM s0 m =3D runSM s0 (observe m)
--
-- the state
--
type Bit =3D Int
data CState =3D CState
{ ok :: Bool,
remaining_data :: [Bit],
history :: [String] -- log, kept in reverse
} deriving Show
initState xs =3D CState True xs []
-- prepend a message in the log
logit :: CState -> String -> CState
logit s logmsg =3D s { history =3D logmsg : (history s) }
--
-- matching action
--
match_bits :: [Bit] -> NDSM CState ()
match_bits xs =3D do
s <- readNDSM
let s' =3D logit s ("attempt match_bits " ++ show xs
++ " remaining: " ++ show (remaining_data s))
s'' =3D if xs =3D=3D take (length xs) (remaining_data s')
then
s' { remaining_data =3D drop (length xs) =
(remaining_data s') }
else
s' { ok =3D False }
if ok s''
then updateNDSM (\s -> s'')
else trace (unlines $ "MATCH FAILED":(reverse $ history s'')) =
M.mzero
--
-- test routines
--
-- just fine
match_1 =3D
(match_bits [1] `M.mplus` match_bits [0])=20
>> match_bits [1]
-- this one only rewinds past the [0] attempt, not the [1] attempt
match_2 =3D
( (match_bits [1] >> match_bits [0])
`M.mplus` match_bits [1, 1] )
c :: [Bit] -> NDSM CState () -> ([Bit], [String])
c h hspec =3D=20
let (v, s) =3D runNDSM (initState h) hspec in
case (ok s) of True -> ([], "ok":(reverse $ history s))
_ -> ([(negate)1], ["fail"])
--------------InterScan_NT_MIME_Boundary
Content-Type: text/plain;
name="RMRL-Disclaimer.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="RMRL-Disclaimer.txt"
Registered Office: Roke Manor Research Ltd, Siemens House, Oldbury, Bracknell,
Berkshire. RG12 8FZ
The information contained in this e-mail and any attachments is confidential to Roke
Manor Research Ltd and must not be passed to any third party without permission. This
communication is for information only and shall not create or change any contractual
relationship.
--------------InterScan_NT_MIME_Boundary--