Developer Data Modeling Mistakes: From Postgres to NoSQL
10. haskell Modules
1. Modules
Sebastian Rettig
A Haskell module is aa collection of related functions,
A Haskell module is collection of related functions,
types and typeclasses.
types and typeclasses.
2. 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)
3. Haskell Features
● Pure Functional Programming Language
● Lazy Evaluation
● Pattern Matching and Guards
● List Comprehension
● Type Polymorphism
● Curried Functions
4. 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!
5. 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
6. 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]
7. 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)
8. 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
9. 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 :: * -> * -> * -> *
10. 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 !
11. 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
12. 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
13. 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]
14. 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
15. Functor Typeclass (1)
class Functor f where
fmap :: (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 [] where
fmap = map
– Example: fmap (*2) [2,3,4] returns [4,6,8]
16. Functor Typeclass (2)
class Functor f where
fmap :: (a -> b) -> f a -> f b
● Instance for Maybe
instance Functor Maybe where
fmap g (Just x) = Just (g x)
fmap g Nothing = Nothing
● Example:
– fmap (+3) Nothing returns Nothing
– fmap (+3) (Just 4) returns (Just 7)
17. 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
18. 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 b
f <$> x = fmap f x
19. Applicative Functor (2)
● Instance for Maybe
instance Applicative Maybe where
pure = Just
Nothing <*> _ = Nothing
(Just f) <*> something = fmap f something
● Instance for IO
instance Applicative IO where
pure = return
a <*> b = do
f <- a
x <- b
return (f x)
20. 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 = do
a <- (++) <$> getLine <*> getLine
putStrLn $ "The two lines concatenated is: " ++ a
21. 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
22. 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
23. 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)