• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
09. haskell Context
 

09. haskell Context

on

  • 172 views

 

Statistics

Views

Total Views
172
Views on SlideShare
172
Embed Views
0

Actions

Likes
1
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    09. haskell Context 09. haskell Context Presentation Transcript

    • Context Sebastian RettigAn applicative value can be seen as aa value with An applicative value can be seen as value with an added context. - - A fancy value. an added context. A fancy value.
    • 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
    • Nice to remember (1) Typeclasses:● define properties of the types● like an interface – Eq can be compared – Ord can be ordered (>, <, >=, <=) (extending Eq) – Show can be shown as string – Read opposite of Show – Enum sequentially ordered types (can be enumerated and usable in List-Ranges [a..e])
    • Nice to remember (2) 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 (3) 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 (4) 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
    • Type Refresher (1) create a Type:● data MyVector = Nirvana | Single Int | Tuple Int Int | Triple Int Int Int● MyVector is the Type● Nirvana, Single, Tuple, Triple are Type Constructors● Type Constructors are normal functions :t Single is Single :: Int -> MyVector● Type Constructors can have Parameters (values) Single, Tuple, Triple have 1, 2 and 3
    • Type Refresher (2) create a Type with Record Syntax:● data MyVector2 = Nirvana2 | Single2 {x :: Int} | Tuple2 {x :: Int, y :: Int} | Triple2 {x :: Int, y :: Int, z :: Int}● Nirvana2, Single2, Tuple2, Triple2 are Type Constructors● x, y, z are selectors functions who lookup specific fields in the data type → like GET functions :t x is x :: MyVector2 -> Int● e.g.: foo = Single2 {x=4} x foo returns 4 :t foo returns foo :: MyVector2
    • Type Refresher (3) to make the Type more generic:● data MyVector3 a = Nirvana3 | Single3 {x :: a} | Tuple3 {x :: a, y :: a} | Triple3 {x :: a, y :: a, z :: a}● a is type parameter and selector x has the following header :t x is x :: MyVector3 a -> a● if we want to use this type, we have to set the Type parameter OR let Haskell detect the Type parameter● e.g.: foo = Single3 {x=4} :t foo returns foo :: MyVector3 Integer● e.g.: foo = Nirvana3 :t foo returns foo :: MyVector3 a
    • Type Refresher (4) a Type can have more than one Type parameter:● data MyVector4 a b c = Nirvana4 | Single4 {x :: a} | Tuple4 {x :: a, y :: b} | Triple4 {x :: a, y :: b, z :: c}● a, b, c are type parameter, selector x has header :t x is x :: MyVector4 a b c -> a● e.g.: foo = Single4 {x=4} :t foo returns foo :: MyVector4 Integer b c● e.g.: foo = Nirvana4 :t foo returns foo :: MyVector4 a b c● → Partial Application!
    • 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 how much parameters a type has● GHCi- Command :k● :k MyVector returns MyVector :: *● :k MyVector2 returns MyVector2 :: *● :k MyVector3 returns MyVector3 :: * -> *● :k MyVector4 returns MyVector4 :: * -> * -> * -> *● :k MyVector3 Int returns MyVector3 Int :: *● :k MyVector4 Int Int returns MyVector4 Int Int :: * -> *
    • Useful Types● Maybe: data Maybe a = Nothing | Just a – for operations, which can fail – contains data of type a (Just a) or Nothing – good for handling e.g. Hashmap lookup● Either: data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show) – can contain type a or type b – Left for e.g. Error Messages, Right for value – BUT why is Error Message the first parameter?
    • Implement Membership (1)● Lets refresh again how to implement a Typeclass- Membership:● first the definition of Typeclass Eq: :i Eq class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool -- Defined in GHC.Classes● What is a ? → a is used by (==) and (/=) as parameter● → needs to be a fully applied type (concrete type)● → :k must return *
    • Implement Membership (2)● But how can we make MyVector3 a member of Eq ?● → we have to make MyVector3 fully applied type, e.g.: instance Eq (MyVector3 Int) where Nirvana3 == Nirvana3 = True Single3 {x=x1} == Single3 {x=x2} = (x1 == x2) ...● Or with using generic Type Parameter: instance Eq (MyVector3 a) where Nirvana3 == Nirvana3 = True Single3 {x=x1} == Single3 {x=x2} = (x1 == x2) ...● do a has Type-Class restrictions? If yes, which?
    • Implement Membership (3)● And what about that? instance Eq MyVector3 where Nirvana3 == Nirvana = True Single3 {x=x1} == Single {x=x2} = (x1 == x2) ...● Is this membership correct?
    • Functor Typeclass (1) class Functor f where fmap :: (a -> b) -> f a -> f b● 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 → the type variable can change!● Instance for List: instance Functor [] where fmap = map – Example: fmap (*2) [2,3,4] returns [4,6,8]
    • 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) – fmap (show) (Just 4) returns (Just “4”)
    • Functor Typeclass (3) class Functor f where fmap :: (a -> b) -> f a -> f b● Instance for Either instance Functor (Either a) where fmap f (Right x) = Right (f x) fmap f (Left x) = Left x● Either is a type with kind * -> * -> * !● → we have to permanently include the first parameter in the instance (partial application)● → fmap only maps over the second Type-Parameter!● → Left Type-Constructor is often used for Error Messages
    • Functor Typeclass (4) 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)● lets 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
    • Lifting a Function● 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 normal function which gets a Functor and returns a Functor● → we move the function inside the Type and operate on type variables● → we lift the function up to the type → normal function can work with complex types
    • 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
    • Applicative Functor (2) class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b● Instance for Maybe instance Applicative Maybe where pure = Just Nothing <*> _ = Nothing (Just f) <*> something = fmap f something● Example: – Just (+3) <*> Just 9 returns Just 12 – pure (+3) <*> Just 10 returns Just 13 – Just (++"hah") <*> Nothing returns Nothing
    • Applicative Functor (3) class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b● Instance for [] instance Applicative [] where pure x = [x] fs <*> xs = [f x | f <- fs, x <- xs]● Example: – [(*0),(+100),(^2)] <*> [1,2,3] returns [0,0,0,101,102,103,1,4,9] – pure "Hey" :: [String] returns ["Hey"] – [(+),(*)] <*> [1,2] <*> [3,4] returns [4,5,5,6,3,4,6,8]
    • Applicative Functor (4)● pure f <*> x equals fmap f x● → in Control.Applicative exists a specific function (<$>) :: (Functor f) => (a -> b) -> f a -> f b f <$> x = fmap f x● So we can do the same much prettier: (++) <$> Just "johntra" <*> Just "volta" returns Just "johntravolta" (++) <$> ["ha","heh","hmm"] <*> ["?","!","."] returns ["ha?", "ha!", "ha.", "heh?", "heh!", "heh.", "hmm?", "hmm!", "hmm."]
    • Applicative Functor (5) class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b● Instance for IO instance Applicative IO where pure = return a <*> b = do f <- a x <- b return (f x)
    • Applicative Functor (6) Example for IO:● instead of writing this: myAction :: IO String myAction = do a <- getLine b <- getLine return $ a ++ b● we can write this: myAction :: IO String myAction = (++) <$> getLine <*> getLine
    • Applicative Context● Applicative Types can bee seen as Types with 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 dont need to pattern match against the Context in every operation we use in our functions!
    • Lifting a Function (Applicative)● Function lifting in for 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)