Outle Doma Specific Languages Lecture 2: The State Monad and an Imperative DSL Verónica Gaspes ceres School of Information Science, Computer and Electrical Engeerg February 2 Programmg with monads Computations The Monad class Usg monads and the do notation Controllg a Robot The language Implementation QuickCheck Results and more... A little language data Term = Con Int Div Term Term derivg Show eval :: Term -> Int eval (Con x) = x eval (Div t1 t2) = eval t1 div eval t2 Here is a term: answer = Div (Div (Con 1972)(Con 2))(Con 23) Here is how to evaluate it: eval answer And the result: 42 How do we modify eval to count the number of divisions or to output a trace? Addg output Outputg a trace type O a = (Output, a) type Output = Strg evaltrace :: Term -> O Int evaltrace (Con x) = (le (Con x) x, x) evaltrace (Div t1 t2) = let (s1,x1) = evaltrace t1 (s2,x2) = evaltrace t2 (s1++s2++le(div t1 t2)(x1 div x2), x1 div x2) Would it have been easier to extend a C program?
Addg state Countg the number of divisions type S a = State -> (a, State) type State = Int evalcount :: Term -> S Int evalcount (Con x) c = (x,c) evalcount (Div t1 t2) c = let (x1,c1) = evalcount t1 c (x2,c2) = evalcount t2 c1 (x1 div x2, c2+1) Would it have been easier to extend a C program? Sequencg It is a matter of programmg style! We want to capture the possibility of calculatg a result while dog somethg else way that makes it easy to sequence! The class Monad is an attempt at this The Monad class class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b a is the type of values we are terested. m is the type constructor that captures the extra thgs we want to do. The bd operator >>= >>= for eval with output (>>=) :: m a -> (a -> m b) -> m b do notation calc >>= f do val <- calc f val Will be defed differently for the different types m. Calculates accordg to calc. Results some compound that cludes the value val. f val can now be used to calculate! data O a = O Output a type Output = Strg return :: a -> O a (>>=) :: O a -> (a -> O b) -> O b return x = O "" x calc >>= f = let O s1 x1 = calc O s2 x2 = f x1 O (s1++s2) x2
Evaluatg and dog output Defition of evaltrace evaltrace :: Term -> O Int evaltrace (Con x) = do out (le (Con x) x) return x evaltrace (Div t1 t2) = do v1 <- evaltrace t1 v2 <- evaltrace t2 out (le (Div t1 t2) (v1 div v2)) return (v1 div v2) Evaluatg and countg Defition of evalcount evalcount :: Term -> S Int evalcount (Con x) = return x evalcount (Div t1 t2) = do v1 <- evalcount t1 v2 <- evalcount t2 c return (v1 div v2) Outputg without computg out :: Output -> O () out s = O s () Countg without computg c :: S () c = S (\x -> ((),x+1)) The state monad An imperative language The last one is an example of a very useful monad because it is related to imperative programmg: Values are computed while changg a global state. We will now see how to use a state monad to implement a little embedded DSL. The language is meant to control a robot livg a grid. data S a = S (State -> (a, State)) A robot program Executg it return :: a -> S a (>>=) :: S a -> (a -> S b) -> S b return x = S (\s->(x,s)) calc >>= st = S (\s -> let S f = calc (x1,s1) = f s S g = st x1 g s1) firstprogram = do move turnleft move move Ma> run firstprogram s0 g0 At (0,1) facg North with 0 cos At (-1,1) facg West with 0 cos At (-2,1) facg West with 0 cos Execution changes the state of the robot and produces some output!
A language to control a robot Atomic actions turnleft turnright turnto move pickco dropco Atomic state spection onco cos direction blocked Control ifthen ifthenelse while Boolean operations * &* neg >* <* The state of the robot The robot we plan to control lives a grid world In the grid the robot is characterized by its position, the direction it faces. Moreover, at some positions there are cos, and this is nown to the robot. The robot collects cos a pocket type Position = (Int, Int) data Direction = North East South West type Treasure = [Position] type Pocket = Int data RobotState = RobotState Position Direction Treasure Pocket ThetypeofRobotCommands Commands to the robot will change its state and will produce some output. Some of them will also compute terestg values! Robot commands data Robot a = Robot (RobotState -> Grid -> IO(RobotState,a)) stance Monad Robot where return a = Robot (\s _ -> return (s,a)) Robot sf0 >>= f = Robot $ \s0 g -> do (s1,a1) <- sf0 s0 g let Robot sf1 = f a1 (s2,a2) <- sf1 s1 g return (s2,a2) Implementg some RobotCommands atomic actions turnto :: Direction -> Robot() turnto d = updatestate stateturnto where stateturnto (RobotState x y z u) = RobotState x d z u Most commands will result changg the state or spectg the state, so we defe Auxiliary for implementation updatestate u = Robot (\s _ -> return (u s,())) querystate q = Robot (\s _ -> return (s, q s))
Implementg some RobotCommands Boolean blocked :: Robot Bool blocked = Robot (\s g -> return (s, stateblocked s g)) stateblocked (RobotState p d ) g=isblocked d (g!p) isblocked North (True, _, _, _) = False isblocked East (_, True, _, _) = False isblocked South (_, _, True, _) = False isblocked West (_, _, _, True) = False isblocked = True neg :: Robot Bool -> Robot Bool neg r = do b <- r return (not b) Implementg some RobotCommands Control ifthenelse :: Robot Bool -> Robot a -> Robot a -> Robot a ifthenelse p r1 r2 = do c <- p if c then r1 else r2 ifthen p r = ifthenelse p r (return ()) while :: Robot Bool -> Robot () -> Robot () while p r = ifthen p step where step = do r while p r QuickCheck, yet another monadic DSEL QuickCheck, yet another monadic DSEL A problem Software testg can be automated usg specification based testg combation with random data generation A solution A DSEL to write specifications, a DSEL to generate data, a program that automates testg! John Huges and Koen Claesen, 350 les of haskell code. Properties Bool Bool ==> Prop forall Gen $ \x-> Prop collect expr Prop The tool quickcheck property Data generators return expr do x1 <- Gen. xn <- Gen Gen arbitrary oneof [Gen] frequency [(Int,Gen)]
Summary We discussed Monads as a way of structurg programs tha express computations. We used a State Monad to implement a little imperative language. We briefly discussed a language for automatic specification based testg. Outlook We will look at how to embedd a compiler haskell.