Skip to content

Instantly share code, notes, and snippets.

@WillNess
Last active December 15, 2015 01:49
Show Gist options
  • Select an option

  • Save WillNess/5182621 to your computer and use it in GitHub Desktop.

Select an option

Save WillNess/5182621 to your computer and use it in GitHub Desktop.
{- 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
{- 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
{- 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
{- 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
{- 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