- module Main where 
-   
- -- 
- -- In order to use "do" notation, we need to declare instances 
- -- of the Monad typeclass. In order to do that we must jump through 
- -- some hoops: 
- --    * We need a name for the datatype we are using (hence the new "Counter" type) 
- --    * We also must declare instances of Functor and Applicative 
- --      (this is something that changed in Haskell 7.10. 
- --       See https://w...content-available-to-author-only...l.org/Functor-Applicative-Monad_Proposal ) 
- --      (Applicative's "pure" is the same as Monad's "return") 
- --  
-   
- -- Integer arithmetic with (+) and (/) 
- data Term =  
-     | Plus Term Term 
-     | Div Term Term 
-   
- -- 
- -- Basic evaluator 
- -- 
-   
- eval (N n) = n 
- eval (Plus t1 t2) = eval t1 +     eval t2 
- eval  (- Div t1 t2 )  =-  eval t1 ` div- ` eval t2 
-   
- -- 
- -- Evaluator that counts the number of operations 
- -- 
-   
- newtype-  Counter a  =-  Counter  (Int -> (Int,-  a ))
 
-   
- unCounter  ::-  Counter a  -> (Int -> (Int,-  a ))
- unCounter (Counter f) = f 
-   
-     -- fmap :: (a -> b) -> Counter a -> Counter b 
-   
- instance Applicative Counter where 
-     -- pure :: a -> Counter a 
-   
-     -- Counter (a -> b) -> Counter a -> Counter b 
-   
- instance Monad-  Counter  where
 
-     -- (>>=) :: Counter a -> (a -> Counter b) -> Counter b 
-   
- runC  ::-  Counter a  -> Int -> (Int,-  a )
-   
- inc :: Counter () 
-   
- evalWithCount  ::-  Term  -> (Int, Int)
- evalWithCount t = runC (eval' t) 0 
-   where 
-     eval' ::-  Term  ->-  Counter  Int
 
-     eval' (N n) = 
-         return n 
-     eval' (Plus t1 t2) = do 
-         n1 <- eval' t1 
-         n2 <- eval' t2 
-         inc 
-     eval' (Div t1 t2) = do 
-         n1 <- eval' t1 
-         n2 <- eval' t2 
-         inc 
-         return (n1 `div` n2) 
-   
- -- 
- -- Evaluator that catches division by zero 
- -- 
- -- Returns (Ok n) in case of success 
- -- Returns (Error "Division by zero") otherwise 
- -- 
-   
-   
- data Result a = Error String | Ok a deriving Show 
-   
- instance Functor Result where 
-     -- fmap :: (a -> b) -> Result a -> Result b 
-     fmap f r = undefined 
-   
- instance Applicative Result where 
-     -- pure :: a -> Result a 
-     pure n = undefined 
-   
-     r1 <*> r2 = undefined 
-   
- instance Monad Result where 
-     -- (>>=) :: Result a -> (a -> Result a) -> Result b 
-     m >>= f = undefined 
-   
- throw :: String -> Result a 
- throw s = undefined 
-   
- evalChecked :: Term -> Result Int 
- evalChecked (N n) = 
-     return n 
- evalChecked (Plus t1 t2) = do 
-     n1 <- evalChecked t1 
-     n2 <- evalChecked t2 
-     return (n1 + n2) 
- evalChecked (Div t1 t2) = do 
-     n1 <- evalChecked t1 
-     n2 <- evalChecked t2 
-     if n2 == 0 then 
-         throw "Division by zero" 
-     else 
-         return (n1 `div` n2) 
-   
- main = print (undefined::String) 
-