1 / 18

More Monads

More Monads. The list monad serves as a monad for non deterministic computations. A result [1,2,3] can be seen as the three potential outcomes of a non deterministic computation. [] indicates that the computation fails and no result is produced. instance Monad [] where      

davidddavis
Download Presentation

More Monads

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. More Monads The list monad serves as a monad for non deterministic computations. A result [1,2,3] can be seen as the three potential outcomes of a non deterministic computation. [] indicates that the computation fails and no result is produced. instance Monad [] where       return x = [x]       xs >>= f = concat (map f xs) Example: do  x <- [1,2,3] [-x,x] 

  2. List Monad class Monad m => MonadPlus m where    mzero :: m a       mplus :: m a -> m a -> m a instance MonadPlus [] where       mzero = [] mplus = (++)  guard :: (MonadPlus m) => Bool -> m ()   guard True = return ()   guard False = mzero do x <- [1..50]  guard ('7' `elem` show x)  return x

  3. Example: Moves of a knight on a chess board. type KnightPos = (Int,Int)   moveKnight :: KnightPos -> [KnightPos]   moveKnight (c,r) =  do (c',r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1),              (c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2)]   guard (c' `elem` [1..8] && r' `elem` [1..8])   return (c',r') in3 :: KnightPos -> [KnightPos] in3 start = do first <- moveKnight start second <- moveKnight first moveKnight second canReachIn3 :: KnightPos -> KnightPos -> Bool canReachIn3 start end = end `elem` in3 start

  4. Some useful functions for Monads sequence :: Monad m => [m a] -> m [a] join :: Monad m => m (m a) -> m a filterM :: Monad m => (a -> m Bool) -> [a] -> m [a] What does the following compute? filterM (\x -> [True, False]) [1,2,3]

  5. Writer Monad The Writer monad can be used for logging events during a computation. Consider the following function that computes a result and produces a log entry about the computation. isBigGang :: Int -> (Bool, String) isBigGang x = (x > 9, "Compared gang size to 9. ") Combining results and simulateneously updating the log can be done by The following function: applyLog :: (a,String) -> (a -> (b,String)) -> (b,String) applyLog (x,log) f = let (y,newLog) = f x in (y,log ++ newLog)

  6. Writer Monad The previous example does not depend on the fact that the log is a string. As long as there is an empty log and two log entries can be combined into a single entry this will work, i.e., log entries form a monoid. class Semigroup a => Monoid a where mempty :: a mappend :: a -> a -> a applyLog :: Monoid m => (a,m) -> (a -> (b,m)) -> (b,m) applyLog (x,log) f = let (y,newLog) = f x in (y,log `mappend` newLog)

  7. Writer Monad The Writer Monad can be implemented as: newtype Writer w a = Writer { runWriter :: (a, w) } instance (Monoid w) => Monad (Writer w) where return x = Writer (x, mempty) (Writer (x,v)) >>= f = let (Writer (y, v')) = f x in Writer (y, v `mappend` v') In Haskell WriterT is implemented as a monad transformer and Writer as An instantiation of WriterT with the identity monad. type Writer w = WriterT w Identity

  8. tell :: Monoid w => w -> Writer w () Using the Writer monad the example can be implemented as follows: isBigGang :: Int -> Writer String Bool isBigGang x = do tell "Compared gang size to 9. " return (x > 9) smallGang :: Writer String Int smallGang = do tell "Smallish gang. " return 3 Example: test3 = do n <- smallGang isBigGang n

  9. Using Writer gcd' :: Int -> Int -> Writer [String] Int gcd' a b | b == 0 = do tell ["Finished with " ++ show a] return a | otherwise = do tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)] gcd' b (a `mod` b) fst $ runWriter (gcd' 8 3) returns 1.

  10. mapM_ putStrLn $ snd $ runWriter (gcd' 8 3) prints: 8 mod 3 = 2 3 mod 2 = 1 2 mod 1 = 0 Finished with 1 This implementation is fast because it combines the log entry with brackets to the right, i.e., using the following pattern: a ++ (b ++ (c ++ (d ++ (e ++ f))))

  11. Now consider: gcdReverse :: Int -> Int -> Writer [String] Int gcdReverse a b | b == 0 = do tell ["Finished with " ++ show a] return a | otherwise = do result <- gcdReverse b (a `mod` b) tell [show a ++ " mod " ++ show b ++ " = " ++ show (a `mod` b)] return result

  12. mapM_ putStrLn $ snd $ runWriter (gcdReverse 8 3) now prints: Finished with 1 2 mod 1 = 0 3 mod 2 = 1 8 mod 3 = 2 This implementation is slow because it combines the log entry with brackets to the left, i.e., using the following pattern: ((((a ++ b) ++ c) ++ d) ++ e) ++ f

  13. DiffLists newtype DiffList a = DiffList { getDiffList :: [a] -> [a] } toDiffList :: [a] -> DiffList a toDiffList xs = DiffList (xs++) fromDiffList :: DiffList a -> [a] fromDiffList (DiffList f) = f [] instance Monoid (DiffList a) where mempty = DiffList (\xs -> [] ++ xs) (DiffList f) `mappend` (DiffList g) = DiffList (\xs -> f (g xs))

  14. (toDiffList [1,2] `mappend` toDiffList [3,4]) `mappend` toDiffList [5,6] → DiffList (\xs -> ([1,2]++) (([3,4]++) xs)) `mappend` toDiffList [5,6] → DiffList (\xs -> ([1,2]++) (([3,4]++) (([5,6]++) xs))) toDiffList [1,2] `mappend` (toDiffList [3,4]) `mappend` toDiffList [5,6]) → toDiffList [1,2] `mappend` DiffList (\xs -> ([3,4]++) (([5,6]++) xs)) → DiffList (\xs -> ([1,2]++) (([3,4]++) (([5,6]++) xs))) fromDiffList (DiffList (\xs -> ([1,2]++) (([3,4]++) (([5,6]++) xs)))) → (\xs -> ([1,2]++) (([3,4]++) (([5,6]++) xs)))) [] → [1,2]++([3,4]++([5,6]++[]))

  15. Further Features of HaskellRecords data Customer = Customer { customerID :: Int, customerName :: String, customerAddress :: Address } The declaration defines the new data type Customer and its constructor Customer :: Int -> String -> Address -> Customer. In addition it also defines the following functions: customerID :: Customer -> Int customerName :: Customer -> String customerAddress :: Customer -> Address

  16. myCustomer = Customer 1234 "Peter Pan" neverland Or alternatively: myCustomer = Customer { customerID = 1234, customerName = "Peter Pan", customerAddress = neverland }

  17. Concurrency/Threads Creating a thread: forkIO :: IO () -> IO ThreadId Example: import Control.Concurrent (forkIO) import qualified Data.ByteString.Lazy as L import Codec.Compression.GZip (compress) main = do putStr "Enter a file to compress> " name <- getLine if null name then return () else do content <- L.readFile name forkIO (compressFile name content) main where compressFile path = L.writeFile (path ++ ".gz") . compress

  18. Foreign Function Interface import Foreign import Foreign.C.Types foreign import ccall "math.h sin" c_sin :: CDouble -> CDouble Points to consider: • Side-effects in C function • Use monad IO • Thread safe code • Multiple threads are extremely common in Hakell code!

More Related