Advertisement
Guest User

goto in Haskell

a guest
Aug 2nd, 2013
594
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. {-# LANGUAGE GADTs #-}
  2.  
  3. import Data.Map as Map
  4. import Control.Monad.Trans.Either
  5. import qualified Control.Monad.Trans.Class as Trans
  6. import Control.Monad (liftM)
  7.  
  8. data GoTo k m r where
  9.   Label :: k -> GoTo k m ()
  10.   GoTo :: k -> GoTo k m ()
  11.   Lift :: m a -> GoTo k m ()
  12.   Return :: a -> GoTo k m a
  13.   Seq :: GoTo k m () -> GoTo k m b -> GoTo k m b
  14.  
  15. showgo :: (Show k, Show r) => GoTo k m r -> String
  16. showgo (Label k) = "  " ++ show k ++ " <---"
  17. showgo (GoTo k)  = "  " ++ "---> " ++ show k
  18. showgo (Lift m)  = "  prim"
  19. showgo (Return a) = "  val " ++ show a
  20. showgo (Seq m1 m2) = showgo m1 ++ ";\n" ++ showgo m2
  21.  
  22. instance (Show k, Show r) => Show (GoTo k m r) where
  23.   show p = "Program {\n" ++ showgo p ++ ";\n}"
  24.  
  25. label :: k -> GoTo k m ()
  26. label = Label
  27.  
  28. lift :: m a -> GoTo k m ()
  29. lift = Lift
  30.  
  31. goto :: k -> GoTo k m ()
  32. goto = GoTo
  33.  
  34. skip :: Monad m => m ()
  35. skip = return ()
  36.  
  37. instance Monad m => Monad (GoTo k m) where
  38.   return x = Return x
  39.   m0 >>= f = case m0 of
  40.     Label k   -> Seq (Label k) (f ())
  41.     GoTo k    -> Seq (GoTo k) (f ())
  42.     Lift m    -> Seq (Lift m) (f ())
  43.     Return x  -> f x
  44.     Seq m1 m2 -> Seq m1 (m2 >>= f)
  45.  
  46. labels :: (Ord k) => GoTo k m () -> Map k (GoTo k m ())
  47. labels = go Map.empty (Return ()) where
  48.   go ls rest (Label k) = Map.insert k (Seq (Label k) rest) ls
  49.   go ls _ (GoTo _) = ls
  50.   go ls _ (Lift _) = ls
  51.   go ls _ (Return _) = ls
  52.   go ls rest (Seq m1 m2) = go ls' rest m2 where
  53.    ls' = go ls (Seq m2 rest) m1
  54.  
  55. data TerminationCode k
  56.   = Success
  57.   | NoSuchLabel k
  58.   deriving Show
  59.  
  60. usesGoTo :: (Ord k, Monad m) => GoTo k m () -> m (TerminationCode k)
  61. usesGoTo m0 = liftM fromEither $ runEitherT $ go m0 where
  62.   go (Label _) = skip
  63.   go (GoTo k) = case Map.lookup k ls of
  64.     Nothing -> EitherT $ return $ Left k
  65.     Just there -> go there -- Find it on the map? Go there. :)
  66.   go (Lift m) = Trans.lift m >> skip
  67.   go (Return ()) = skip
  68.   go (Seq m1 m2) = case m1 of
  69.     GoTo{} -> go m1 -- goto discards its 'current continuation' m2
  70.     _ -> go m1 >> go m2
  71.  
  72.   -- static analysis!
  73.   ls = labels m0
  74.  
  75.   fromEither (Left k) = NoSuchLabel k
  76.   fromEither (Right ()) = Success
  77.  
  78. example = do
  79.   goto (1 :: Int)
  80.   label 2
  81.   lift $ putStrLn "two"
  82.   goto 3
  83.   label 1
  84.   lift $ putStrLn "one"
  85.   goto 2
  86.   label 3
  87.   lift $ putStrLn "three"
  88.  
  89. main = usesGoTo example
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement