10. haskell Modules
-
Upload
sebastian-rettig -
Category
Technology
-
view
229 -
download
0
Transcript of 10. haskell Modules
Modules
Sebastian Rettig
A Haskell module is a collection of related functions, types and typeclasses.
A Haskell module is a collection of related functions, types and typeclasses.
Functional Programming
● No Variables● Functions only, eventually stored in
Modules– Behavior do not change, once defined
– → Function called with same parameter calculates always the same result
● Function definitions (Match Cases)● Recursion (Memory)
Haskell Features
● Pure Functional Programming Language● Lazy Evaluation ● Pattern Matching and Guards● List Comprehension● Type Polymorphism● Curried Functions
Nice to remember (1)
Applicative Context:
– Maybe, Either for things which can fail
– [] as non-deterministic result
– IO as values send or get from outside
● Applicative functors allows us to operate in applicative types like normal types and provide the context!
● → We don't need to pattern match against the Context in every operation we use in our functions!
Nice to remember (2)
Typeclasses:● define properties of the types
● an interface for types who have some behavior in common:
– Eq can be compared
– Ord can be ordered (>, <, >=, <=) (extending Eq)
– Show can be shown as string
– Read opposite of Show
– Functor something that can be mapped over
– Applicative handle functions wrapped in a Functor
Nice to remember (3)
Typeclass-Membership:
1. derive from existing Memberships of used types
data Vector2D = Vector Float Float deriving (Show, Eq)
2. implement Membership by your own
instance Show Vector2D where
show Vector a b = “x: ” ++ [a] ++ “ ; y: ” ++ [b]
Nice to remember (4)
Curried Function:
● every function in haskell consumes exactly one parameter and returns a value
● PARTIAL APPLICATION
● so we could write the function header instead of:
max :: (Ord a) => a -> a -> a
● also in the following way:
max :: (Ord a) => a -> (a -> a)
Nice to remember (5)Pointless Style:
● based on partial Application → simpler code
maxWithFour x = max 4 x is the same as
maxWithFour = max 4
● use Function Application ($) to avoid Parenthesis on function call with parameters
sqrt $ 3 + 4 + 9
● use Function Composition (.) to avoid Parenthesis on chaining functions
fn = ceiling . negate . tan . cos . max 50
Nice to remember (6)Kind:
● explains the steps which are necessary to evaluate the data from that type
● → evaluate = the type is fully applied
● can be used to find out the parameter-count of a type
● GHCi- Command :k
● :k Int returns Int :: *
● data MyVector4 a b c = Nirvana4| Single4 {x'' :: a} | Tuple4 {x'' :: a, y :: b} | Triple4 {x'' :: a, y'' :: b, z'' :: c}
:k MyVector4 returns MyVector4 :: * -> * -> * -> *
Nice to remember (7)DO-Notation:
main :: IO ()main = do putStrLn “Say me your Name!” name <- getLine putStrLn $ “Hello” ++ name
● do syntax glues IO actions together
● bind operator <- get the data out of IO and bind result to a placeholder
● :t getLine returns getLine :: IO String
– name has the type String
● ! The last action in a do-block can not be bound !
Nice to remember (8)
Fold & Scan:● foldl :: (a -> b -> a) -> a -> [b] -> a
● foldr :: (a -> b -> b) -> b -> [a] -> b
● scanl :: (a -> b -> a) -> a -> [b] -> [a]
● scanr :: (a -> b -> b) -> b -> [a] -> [b]
● folding is a general approach for simple recursion
● scan is like fold, but returns the accumulator state of every recursion step instead of the accumulator
Modules (1)● types and functions are managed in modules
● main module can load other modules
● prelude.hs loads mostly used modules on startup
● import modules at the beginning of a File:
import Data.List
● Selective Import of only some functions of module
import Data.List (nub, sort)
– import only functions nub and sort
– import Data.List hiding (nub)
– import all functions but not nub
Modules (2)● use qualified imports if you have name conflicts
● often occurs on import modules which are already selective imported by prelude.hs
import Data.Map as M
– use reference to call qualified imports, e.g.
M.filter (>5) [3,6,2]
Modules (3)● create own modules, e.g. File Geometry.hs
module Geometry( sphereVolume, sphereArea) where//Implementation
● modules in a namespace must be in same parent Folder, e.g. module Geometry.Sphere( volume, area) where
– Sphere.hs in folder Geometry
Functor Typeclass (1)class Functor f wherefmap :: (a -> b) -> f a -> f b
● general Interface for things that can be mapped over
● !!! Functor needs Types with kind * -> * !!!
● fmap gets a function and a type and maps the function over the type variable
● Instance for List:
instance Functor [] wherefmap = map
– Example: fmap (*2) [2,3,4] returns [4,6,8]
Functor Typeclass (2)class Functor f wherefmap :: (a -> b) -> f a -> f b
● Instance for Maybe
instance Functor Maybe wherefmap g (Just x) = Just (g x) fmap g Nothing = Nothing
● Example:
– fmap (+3) Nothing returns Nothing
– fmap (+3) (Just 4) returns (Just 7)
Functor Typeclass (3)class Functor f where
fmap :: (a -> b) -> f a -> f b
● Example:
– fmap (+3) (Left 4) returns (Left 4)
– fmap (+3) (Right 4) returns (Right 7)
● what happens, if we try to do that?fmap (+) (Just 4)
● let's look at the type: :t fmap (+) (Just 4)fmap (+) (Just 4) :: Num a => Maybe (a -> a)
● partial application, BUT we can not use the Functor instance on the result Just (4+)
● → we need an extension → Applicative Functors
Applicative Functor (1)class (Functor f) => Applicative f where
pure :: a -> f a(<*>) :: f (a -> b) -> f a -> f b
● pure is a function who wraps a normal value into applicative
– creates a minimal context
● (<*>) takes a functor with a function in it and another functor
– extracts that function from the first functor
– and then maps it over the second one
● pure f <*> x equals fmap f x → specific function exists:
(<$>) :: (Functor f) => (a -> b) -> f a -> f bf <$> x = fmap f x
Applicative Functor (2)● Instance for Maybe
instance Applicative Maybe wherepure = JustNothing <*> _ = Nothing(Just f) <*> something = fmap f something
● Instance for IO
instance Applicative IO wherepure = returna <*> b = do f <- a x <- b return (f x)
Applicative Functor (3)Examples:
● Just (+3) <*> Just 9 returns Just 12
● pure (+3) <*> Just 10 returns Just 13
● Just (++"hah") <*> Nothing returns Nothing
● [(+100),(^2)] <*> [1,2,3] returns [101,102,103,1,4,9]
● pure "Hey" :: [String] returns ["Hey"]
● [(+),(*)] <*> [1,2] <*> [3,4] returns [4,5,5,6,3,4,6,8]
● (++) <$> Just "foo" <*> Just "bar" returns Just "foobar"
● main = doa <- (++) <$> getLine <*> getLineputStrLn $ "The two lines concatenated is: " ++ a
Lifting a Function (Functor)● if we partial apply fmap, the header has the following structure
:t fmap (*2) results in fmap (*2) :: (Num a, Functor f) => f a -> f a
:t fmap (cycle 3) results in fmap (cycle 3) :: (Functor f) => f a -> f [a]
● → this is called lifting a function
● → we can predefine a function which gets a Functor and returns a functor
● → that means, we can bring normal functions inside the Wrapper (Context)
● → we lift the function up into the Context
Lifting a Function (Applicative)● liftA :: Applicative f => (a -> b) -> f a -> f b
– same as fmap
– fmap :: Functor f => (a -> b) -> f a -> f b
● liftA2 :: (Applicative f) => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
– gets a function, with 2 parameters
– operates on 2 Applicatives
– result is also an Applicative
Sources
[1] Haskell-Tutorial: Learn you a Haskell (http://learnyouahaskell.com/, 2012/03/15)
[2] The Hugs User-Manual (http://cvs.haskell.org/Hugs/pages/hugsman/index.html, 2012/03/15)
[3] The Haskellwiki (http://www.haskell.org/haskellwiki, 2012/03/15)