KEMBAR78
09. haskell Context | PDF
Context

           Sebastian Rettig


An 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)
●   Let's 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)
●   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
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 don't 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)

09. haskell Context

  • 1.
    Context Sebastian Rettig An 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.
  • 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
  • 4.
    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'])
  • 5.
    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]
  • 6.
    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)
  • 7.
    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
  • 8.
    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
  • 9.
    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
  • 10.
    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
  • 11.
    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!
  • 12.
    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 :: * -> *
  • 13.
    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?
  • 14.
    Implement Membership (1) ● Let's 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 *
  • 15.
    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?
  • 16.
    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?
  • 17.
    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]
  • 18.
    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”)
  • 19.
    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
  • 20.
    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) ● 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
  • 21.
    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
  • 22.
    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
  • 23.
    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
  • 24.
    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]
  • 25.
    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."]
  • 26.
    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)
  • 27.
    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
  • 28.
    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 don't need to pattern match against the Context in every operation we use in our functions!
  • 29.
    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
  • 30.
    Sources [1] Haskell-Tutorial: Learnyou 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)