Last active
December 15, 2015 01:49
-
-
Save WillNess/5182621 to your computer and use it in GitHub Desktop.
examples from All About Monads
http://web.archive.org/web/20061210172052/http://www.nomaware.com/monads/html/examples.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {- Author: Jeff Newbern | |
| Maintainer: Jeff Newbern <[email protected]> | |
| Time-stamp: <Mon Nov 10 11:59:14 2003> | |
| License: GPL | |
| -} | |
| {- DESCRIPTION | |
| Example 1 - Our first monad | |
| Usage: Compile the code and execute the resulting program. | |
| It will print Dolly's maternal grandfather. | |
| -} | |
| -- everything you need to know about sheep | |
| data Sheep = Sheep {name::String, mother::Maybe Sheep, father::Maybe Sheep} | |
| -- we show sheep by name | |
| instance Show Sheep where | |
| show s = show (name s) | |
| -- comb is a combinator for sequencing operations that return Maybe | |
| comb :: Maybe a -> (a -> Maybe b) -> Maybe b | |
| comb Nothing _ = Nothing | |
| comb (Just x) f = f x | |
| -- now we can use `comb` to build complicated sequences | |
| maternalGrandfather :: Sheep -> Maybe Sheep | |
| maternalGrandfather s = (Just s) `comb` mother `comb` father | |
| fathersMaternalGrandmother :: Sheep -> Maybe Sheep | |
| fathersMaternalGrandmother s = (Just s) `comb` father `comb` mother `comb` mother | |
| mothersPaternalGrandfather :: Sheep -> Maybe Sheep | |
| mothersPaternalGrandfather s = (Just s) `comb` mother `comb` father `comb` father | |
| -- this builds our sheep family tree | |
| breedSheep :: Sheep | |
| breedSheep = let adam = Sheep "Adam" Nothing Nothing | |
| eve = Sheep "Eve" Nothing Nothing | |
| uranus = Sheep "Uranus" Nothing Nothing | |
| gaea = Sheep "Gaea" Nothing Nothing | |
| kronos = Sheep "Kronos" (Just gaea) (Just uranus) | |
| holly = Sheep "Holly" (Just eve) (Just adam) | |
| roger = Sheep "Roger" (Just eve) (Just kronos) | |
| molly = Sheep "Molly" (Just holly) (Just roger) | |
| in Sheep "Dolly" (Just molly) Nothing | |
| -- print Dolly's maternal grandfather | |
| main :: IO () | |
| main = let dolly = breedSheep | |
| in do print (maternalGrandfather dolly) | |
| -- END OF FILE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {- Author: Jeff Newbern | |
| Maintainer: Jeff Newbern <[email protected]> | |
| Time-stamp: <Mon Nov 10 11:58:21 2003> | |
| License: GPL | |
| -} | |
| {- DESCRIPTION | |
| Example 2 - Do notation | |
| Usage: Compile the code and execute the resulting program. | |
| It will print Dolly's maternal grandfather. | |
| -} | |
| -- everything you need to know about sheep | |
| data Sheep = Sheep {name::String, mother::Maybe Sheep, father::Maybe Sheep} | |
| -- we show sheep by name | |
| instance Show Sheep where | |
| show s = show (name s) | |
| -- the Maybe type is already declared as an instance of the Monad class | |
| -- in the standard prelude, so we don't actually need to define it here. | |
| -- just remember that it looks something like this: | |
| -- instance Monad Maybe where | |
| -- Nothing >>= f = Nothing | |
| -- (Just x) >>= f = f x | |
| -- return = Just | |
| -- we can use do-notation to build complicated sequences | |
| maternalGrandfather :: Sheep -> Maybe Sheep | |
| maternalGrandfather s = do m <- mother s | |
| father m | |
| fathersMaternalGrandmother :: Sheep -> Maybe Sheep | |
| fathersMaternalGrandmother s = do f <- father s | |
| gm <- mother f | |
| mother gm | |
| mothersPaternalGrandfather :: Sheep -> Maybe Sheep | |
| mothersPaternalGrandfather s = do m <- mother s | |
| gf <- father m | |
| father gf | |
| -- this builds our sheep family tree | |
| breedSheep :: Sheep | |
| breedSheep = let adam = Sheep "Adam" Nothing Nothing | |
| eve = Sheep "Eve" Nothing Nothing | |
| uranus = Sheep "Uranus" Nothing Nothing | |
| gaea = Sheep "Gaea" Nothing Nothing | |
| kronos = Sheep "Kronos" (Just gaea) (Just uranus) | |
| holly = Sheep "Holly" (Just eve) (Just adam) | |
| roger = Sheep "Roger" (Just eve) (Just kronos) | |
| molly = Sheep "Molly" (Just holly) (Just roger) | |
| in Sheep "Dolly" (Just molly) Nothing | |
| -- print Dolly's maternal grandfather | |
| main :: IO () | |
| main = let dolly = breedSheep | |
| in do print (maternalGrandfather dolly) | |
| -- END OF FILE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {- Author: Jeff Newbern | |
| Maintainer: Jeff Newbern <[email protected]> | |
| Time-stamp: <Mon Nov 10 11:59:36 2003> | |
| License: GPL | |
| -} | |
| {- DESCRIPTION | |
| Example 3 - Using the foldM function - part 1 | |
| Usage: Compile the code and execute the resulting program | |
| with arguments that describe an ancestor. | |
| The program will print the sheep that has that | |
| relationship with Dolly, or Nothing if there is | |
| no such sheep. | |
| Try: ./ex3 mother | |
| ./ex3 father | |
| ./ex3 mother mother father | |
| ./ex3 father mother | |
| -} | |
| import Monad | |
| import System | |
| -- everything you need to know about sheep | |
| data Sheep = Sheep {name::String, mother::Maybe Sheep, father::Maybe Sheep} | |
| -- we show sheep by name | |
| instance Show Sheep where | |
| show s = show (name s) | |
| -- traceFamily is a generic function to find an ancestor | |
| traceFamily :: Sheep -> [ (Sheep -> Maybe Sheep) ] -> Maybe Sheep | |
| traceFamily s l = foldM getParent s l | |
| where getParent s f = f s | |
| -- we can define complex queries using traceFamily in an easy, clear way | |
| paternalGrandmother s = traceFamily s [father, mother] | |
| mothersPaternalGrandfather s = traceFamily s [mother, father, father] | |
| -- this allows the user to name the mother and father functions on the command line | |
| getFunctionByName :: String -> (Sheep -> Maybe Sheep) | |
| getFunctionByName "father" = father | |
| getFunctionByName "mother" = mother | |
| getFunctionByName _ = error "Invalid function name - not 'mother' or 'father'" | |
| -- this builds our sheep family tree | |
| breedSheep :: Sheep | |
| breedSheep = let adam = Sheep "Adam" Nothing Nothing | |
| eve = Sheep "Eve" Nothing Nothing | |
| uranus = Sheep "Uranus" Nothing Nothing | |
| gaea = Sheep "Gaea" Nothing Nothing | |
| kronos = Sheep "Kronos" (Just gaea) (Just uranus) | |
| holly = Sheep "Holly" (Just eve) (Just adam) | |
| roger = Sheep "Roger" (Just eve) (Just kronos) | |
| molly = Sheep "Molly" (Just holly) (Just roger) | |
| in Sheep "Dolly" (Just molly) Nothing | |
| -- we can use monadic operations to build complicated sequences | |
| main :: IO () | |
| main = let dolly = breedSheep | |
| in do args <- getArgs | |
| print $ traceFamily dolly (map getFunctionByName args) | |
| -- END OF FILE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {- Author: Jeff Newbern | |
| Maintainer: Jeff Newbern <[email protected]> | |
| Time-stamp: <Wed Jul 2 16:49:28 2003> | |
| License: GPL | |
| -} | |
| {- DESCRIPTION | |
| Example 4 - Using the foldM function - part 2 | |
| Usage: Compile the code and execute the resulting program | |
| with names of definition files as arguments. | |
| The definition files have the form of a series | |
| of assignments "key = value", one per line. | |
| The assignments from each file are accumulated | |
| and then the final dictionary is printed | |
| as an association list. | |
| -} | |
| import Monad | |
| import IO | |
| import System | |
| import Data.FiniteMap | |
| import Char(isSpace) | |
| -- an Entry is a key and a value, both Strings | |
| data Entry = Entry {key::String, value::String} | |
| -- show an entry as "key = value" | |
| instance Show Entry where | |
| show e = show (key e) ++ " = " ++ (show (value e)) | |
| -- we parse "key = value" strings into Entry values | |
| instance Read Entry where | |
| readsPrec _ s = readsEntry s | |
| readsEntry :: ReadS Entry | |
| readsEntry s = [(Entry (trim key) (trim val), s'') | (key, s') <- [break (=='=') s], | |
| (x:val, s'') <- [break (=='\n') s'] ] | |
| -- remove leading and trailing whitespace | |
| trim :: String -> String | |
| trim s = dropWhile isSpace (reverse (dropWhile isSpace (reverse s))) | |
| -- convenience function | |
| openForReading :: FilePath -> IO Handle | |
| openForReading f = openFile f ReadMode | |
| -- a Dict is just a finite map from strings to strings | |
| type Dict = FiniteMap String String | |
| -- this an auxilliary function used with foldl | |
| addEntry :: Dict -> Entry -> Dict | |
| addEntry d e = addToFM d (key e) (value e) | |
| -- this is an auxiliiary function used with foldM inside the IO monad | |
| addDataFromFile :: Dict -> Handle -> IO Dict | |
| addDataFromFile dict hdl = do contents <- hGetContents hdl | |
| entries <- return (map read (lines contents)) | |
| return (foldl (addEntry) dict entries) | |
| -- this program builds a dictionary from the entries in all files named on the | |
| -- command line and then prints it out as an association list | |
| main :: IO () | |
| main = do files <- getArgs | |
| handles <- mapM openForReading files | |
| dict <- foldM addDataFromFile emptyFM handles | |
| print (fmToList dict) | |
| -- END OF FILE |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {- Author: Jeff Newbern | |
| Maintainer: Jeff Newbern <[email protected]> | |
| Time-stamp: <Wed Jul 2 16:53:12 2003> | |
| License: GPL | |
| -} | |
| {- DESCRIPTION | |
| Example 5 - Using the filterM function | |
| Usage: Compile the code and execute the resulting program | |
| with a number of file and directory names as arguments. | |
| The program will print only the names of the directories. | |
| -} | |
| import Monad | |
| import Directory | |
| import System | |
| -- NOTE: doesDirectoryExist has type FilePath -> IO Bool | |
| -- this program prints only the directories named on the command line | |
| main :: IO () | |
| main = do names <- getArgs | |
| dirs <- filterM doesDirectoryExist names | |
| mapM_ putStrLn dirs | |
| -- END OF FILE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment