Thursday 2 June 2016

Haskell: Functors


Haskell GHC.Base library defines Functor class like below.
class Functor f where
  fmap :: (a -> b) -> f a -> f b

fmap function takes a function, A functor instance as an argument and return another functor instance.

For example
Prelude> (+2) 10
12
Prelude> 
Prelude> (*2) 20
40
Prelude> 
Prelude> (/2) 30
15.0

Observe above snippet, you able to apply the sections (+2), (*2) and (/2) on numbers. Will you able to do the same thing on ‘Just 10’, ‘Just 20’ and ‘Just 30’?

Prelude> (+2) Just 10

<interactive>:28:1:
    Non type-variable argument in the constraint: Num (a -> Maybe a)
    (Use FlexibleContexts to permit this)
    When checking that it has the inferred type
      it :: forall a. (Num a, Num (a -> Maybe a)) => Maybe a
Prelude> 
Prelude> (*2) Just 20

<interactive>:30:1:
    Non type-variable argument in the constraint: Num (a -> Maybe a)
    (Use FlexibleContexts to permit this)
    When checking that it has the inferred type
      it :: forall a. (Num a, Num (a -> Maybe a)) => Maybe a
Prelude> 
Prelude> (/2) Just 30

<interactive>:32:1:
    Non type-variable argument
      in the constraint: Fractional (a -> Maybe a)
    (Use FlexibleContexts to permit this)
    When checking that it has the inferred type
      it :: forall a. (Fractional (a -> Maybe a), Num a) => Maybe a


Here Functor class came into picture.  It defines fmap for Maybe type like below.
instance  Functor Maybe  where
    fmap _ Nothing       = Nothing
    fmap f (Just a)      = Just (f a)

Prelude> fmap (+2) (Just 10) 
Just 12
Prelude> 
Prelude> fmap (*2) (Just 20)
Just 40
Prelude> 
Prelude> fmap (/2) (Just 30)
Just 15.0
Prelude> 
Prelude> fmap (/2) Nothing
Nothing

What is a Functor?

A functor is any data type, that defines how fmap applies to it.
Prelude> :info Functor
class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b
  (<$) :: a -> f b -> f a
    -- Defined in ‘GHC.Base’
instance Functor (Either a) -- Defined in ‘Data.Either’
instance Functor [] -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Functor IO -- Defined in ‘GHC.Base’
instance Functor ((->) r) -- Defined in ‘GHC.Base’
instance Functor ((,) a) -- Defined in ‘GHC.Base’
Prelude> 

Observe above snippet, Maybe, IO, Either all defines how fmap applies to them, so Maybe, IO and Either are functors.


Other Examples
Prelude> fmap length (Just "Hello Haskell")
Just 13
Prelude> 
Prelude> fmap head (Just "Hello Haskell")
Just 'H'
Prelude> 
Prelude> fmap tail (Just "Hello Haskell")
Just "ello Haskell"
Prelude> 
Prelude> fmap (zip [1, 2, 3])  (Just "Hello Haskell")
Just [(1,'H'),(2,'e'),(3,'l')]









Previous                                                 Next                                                 Home

No comments:

Post a Comment