© M. Winter COSC 4P41 – Functional Programming Further Features of Haskell Records 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
© M. Winter COSC 4P41 – Functional Programming myCustomer = Customer 1234 "Peter Pan" neverland Or alternatively: myCustomer = Customer { customerID = 1234, customerName = "Peter Pan", customerAddress= neverland }
© M. Winter COSC 4P41 – Functional Programming 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
© M. Winter COSC 4P41 – Functional Programming 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!
© M. Winter COSC 4P41 – Functional Programming Monad Transformers Motivation: We want to combine the monads IO and Maybe in order to be able to do in/output as well as to catch errors. The result should be a new monad. Bind for IO: (>>=) :: IO a -> (a -> IO b) -> IO b Bind for Maybe: (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b How do we get the new bind??? Solution: Create a monad transformer for Maybe that allows to wrap any monad m around Maybe, i.e., m (Maybe a).
© M. Winter COSC 4P41 – Functional Programming Monad Transformers Properties for Monad Transformers t: 1.t :: (* -> *) -> * -> * 2.instance (Monad m) => Monad (t m) where... 3.instance MonadTrans t where lift :: Monad m => m a -> t m a 4.lift. return = return 5.lift (m >>= f) = lift m >>= (lift. f)
© M. Winter COSC 4P41 – Functional Programming import Control.Monad import Control.Monad.Trans newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) } bindT :: (Monad m) => MaybeT m a -> (a -> MaybeT m b) -> MaybeT m b x `bindT` f = MaybeT (runMaybeT x >>= maybe (return Nothing) (runMaybeT. f)) returnT :: (Monad m) => a -> MaybeT m a returnT = MaybeT. return. return
© M. Winter COSC 4P41 – Functional Programming instance (Monad m) => Monad (MaybeT m) where return = returnT (>>=) = bindT instance MonadTrans MaybeT where lift m = MaybeT (m >>= (return. Just))
© M. Winter COSC 4P41 – Functional Programming Numbering Trees using State Monad newtype StateT s m a = StateT { runStateT :: s -> m (a,s) } type State s = StateT s Identity evalState :: State s a -> s -> a get :: (Monad m) => StateT s m s get :: State s s in the case m = Identity put :: (Monad m) => s -> StateT s m () put :: s -> State s () in the case m = Identity
© M. Winter COSC 4P41 – Functional Programming import Data.List import Control.Monad.Trans.State.Lazy data Tree a = Empty | Node a (Tree a) (Tree a) deriving Show type Table a = [a] tree = Node "Moon" (Node "Ahmet" Empty Empty) (Node "Dweezil" (Node "Ahmet" Empty Empty) (Node "Moon" Empty Empty)) Moon Dweezil Ahmet Moon
© M. Winter COSC 4P41 – Functional Programming numberTree :: Eq a => Tree a -> State (Table a) (Tree Int) numberTree Empty = return Empty numberTree (Node x t1 t2) = do num <- numberNode x nt1 <- numberTree t1 nt2 <- numberTree t2 return (Node num nt1 nt2) numberNode :: Eq a => a -> State (Table a) Int numberNode x = do table <- get case (elemIndex x table) of Nothing -> do put (table++[x]) return $ length table Just n -> return n runProg :: Eq a => Tree a => IO () runProg t = print $ evalState (numberTree t) []
© M. Winter COSC 4P41 – Functional Programming Using State Monad Transform numberNode :: (Eq a, Show a) => a -> StateT (Table a) IO Int numberNode x = do table <- get case (elemIndex x table) of Nothing -> do put (table++[x]) lift $ putStrLn ("New value: " ++ show x) return $ length table Just n -> return n numberTree :: (Eq a, Show a) => Tree a -> StateT (Table a) IO (Tree Int) numberTree …
© M. Winter COSC 4P41 – Functional Programming evalStateT :: (Monad m) => StateT s m a -> s -> m a runProg :: (Eq a, Show a) => Tree a => IO () runProg t = do t <- evalStateT (numberTree t) [] print t Example session: > runProg tree New value: "Moon" New value: "Ahmet" New value: "Dweezil" Node 0 (Node 1 Empty Empty) (Node 2 (Node 1 Empty Empty) (Node 0 Empty Empty))