09. haskell context

30
Context Sebastian Rettig An applicative value can be seen as a value with an added context. - A fancy value. An applicative value can be seen as a value with an added context. - A fancy value.

Upload: sebastian-rettig

Post on 29-Aug-2014

200 views

Category:

Documents


0 download

DESCRIPTION

 

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 (>, =, 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 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 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)