Functors
This presentation is the property of its rightful owner.
Sponsored Links
1 / 20

Functors in Haskell PowerPoint PPT Presentation


  • 74 Views
  • Uploaded on
  • Presentation posted in: General

Functors in Haskell. Adapted from material by Miran Lipovaca. Functors. Functors are a typeclass, just like Ord, Eq, Show, and all the others. This one is designed to hold things that can be mapped over; for example, lists are part of this typeclass. class Functor f where

Download Presentation

Functors in Haskell

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


Functors in haskell

Functors

in Haskell

Adapted from material by Miran Lipovaca


Functors

Functors

Functors are a typeclass, just like Ord, Eq, Show, and all the others. This one is designed to hold things that can be mapped over; for example, lists are part of this typeclass.

classFunctorfwhere

fmap::(a->b)->fa->fb

Only one typeclass method, called fmap. Basically, says: give me a function that takes a and returns b and a “box” with type a inside of it, and I’ll return a “box” with type b inside of it.

1


Functors in haskell

Compare fmap to map:

fmap::(a->b)->fa->fb

map :: (a -> b) -> [a] -> [b]

So map is a lot like a functor! Here, map takes a function and a list of type a, and returns a list of type b.

In fact, can define map in terms of fmap:

instanceFunctor[]where

fmap=map

2


Functors in haskell

Notice what we wrote:

instanceFunctor[]where

fmap=map

We did NOT write “instance Functor [a] where…”, since f has to be a type constructor that takes one type.

Here, [a] is already a concrete type, while [] is a type constructor that takes one type and can produce many types, like [Int], [String], [[Int]], etc.

3


Functors in haskell

Another example:

instanceFunctorMaybewhere

fmapf(Justx)=Just(fx)

fmapfNothing=Nothing

Again, we did NOT write “instance Functor (Maybe m) where…”, since functor wants a type constructor.

Mentally replace the f’s with Maybe, so fmap acts like (a -> b) -> Maybe a -> Maybe b.

If we put (Maybe m), would have (a -> b) -> (Maybe m) a -> (Maybe m) b, which looks wrong.

4


Functors in haskell

Using it:

ghci>fmap(++"HEYGUYSIMINSIDETHE

JUST")(Just"Somethingserious.")

Just"Somethingserious.HEYGUYSIMINSIDETHEJUST"

ghci>fmap(++"HEYGUYSIMINSIDETHE

JUST")Nothing

Nothing

ghci>fmap(*2)(Just200)

Just400

ghci>fmap(*2)Nothing

Nothing

5


Functors in haskell

  • Another example - the tree class.

  • We’ll define a tree to be either:

  • an empty tree

  • an element with a value and two (sub)trees

dataTreea=EmptyTree|

Nodea(Treea)(Treea)

deriving(Show,Read,Eq)

This is slightly different than our last definition. Here, trees will be of the form:

Node 5 (Node 3 (Node 1 EmptyTree EmptyTree) (Node 4 EmptyTree EmptyTree)) (Node 6 EmptyTree EmptyTree)

6


Functors in haskell

Some tree functions:

singleton::a->Treea

singletonx=NodexEmptyTreeEmptyTree

treeInsert::(Orda)=>a->Treea->Treea

treeInsertxEmptyTree=singletonx

treeInsertx(Nodealeftright)

|x==a=Nodexleftright

|x<a=Nodea(treeInsertxleft)right

|x>a=Nodealeft(treeInsertxright)

7


Functors in haskell

And now to find an element in the tree:

treeElem::(Orda)=>a->Treea->Bool

treeElemxEmptyTree=False

treeElemx(Nodealeftright)

|x==a=True

|x<a=treeElemxleft

|x>a=treeElemxright

Note: we deliberately assumed we could compare the elements of the nodes so that we could make this a binary search tree.

If this is an “unordered” tree, would need to search both left and right subtrees.

8


Functors in haskell

An example run:

ghci>letnums=[8,6,4,1,7,3,5]

ghci>letnumsTree=foldrtreeInsertEmptyTreenums

ghci>numsTree

Node5(Node3(Node1EmptyTreeEmptyTree)(Node4EmptyTreeEmptyTree))(Node7(Node6EmptyTreeEmptyTree)(Node8EmptyTreeEmptyTree))

9


Functors in haskell

Back to functors:

If we looked at fmap as though it were only for trees, it would look something like:

(a -> b) -> Tree a -> Tree b

We can certainly phrase this as a functor, also:

instanceFunctorTreewhere

fmapfEmptyTree=EmptyTree

fmapf(Nodexleftsubrightsub)=

Node(fx)(fmapfleftsub)

(fmapfrightsub)

10


Functors in haskell

Using the tree functor:

ghci>fmap(*2)EmptyTree

EmptyTree

ghci>fmap(*4)(foldrtreeInsert

EmptyTree[5,7,3,2,1,7])

Node28(Node4EmptyTree(Node8EmptyTree(Node12EmptyTree(Node20EmptyTreeEmptyTree))))EmptyTree

11


Functors in haskell

  • Some rules:

  • The type has to have a kind of * -> *, which means it takes only 1 concrete type as a parameter. Example:

ghci>:kMaybe

Maybe::*->*

12


Functors in haskell

If a type takes 2 parameters, like Either:

dataEitherab=Lefta

|Rightb

deriving(Eq,Ord,Read,Show)

ghci>Right20

Right20

ghci>:tRight'a'

Right'a'::EitheraChar

ghci>:tLeftTrue

LeftTrue::EitherBoolb


Functors in haskell

Then the signature :k looks like this:

ghci>:kEither

Either::*->*->*

For this situation, we need to partially apply the type constructor until it takes only 1 input.

Remember, Haskell is good at partial evaluations!

instance Functor (Either a) where

fmap :: (b -> c) -> Either a b -> Either a c


Functors in haskell

Another functor: the <- in the IO class

instanceFunctorIOwhere

fmapfaction=do

result<-action

return(fresult)

  • Comments:

  • The result of an IO action must be an IO action, so we’ll use do to glue our 2 things together.

  • We can use this to make our code more compact, since we won’t need to explicitly “unpack” the IO.

  • Now (for example) the command:

    • fmap (++ “!”) getline

    • Will behave just like getline, but with a ! at the end of the line


Functors in haskell

Example: program 1

main=doline<-getLine

letline'=reverseline

putStrLn$"Yousaid"++line'++

"backwards!"

With fmap:

main=doline<-fmapreversegetLine

putStrLn$"Yousaid"++line++

"backwards!"


Functors in haskell

There are two rules that every functor should obey. Note that these aren’t enforced by Haskell, but they are important!

First: If we map the identity function over a functor, then the functor we get back should be the same as the original functor. So: fmap id = id.

ghci>fmapid(Just3)

Just3

ghci>id(Just3)

Just3

ghci>fmapid[1..5]

[1,2,3,4,5]

ghci>id[1..5]

[1,2,3,4,5]


Functors in haskell

Second rule: composing two functions and then mapping the resulting function over a functor should be the same as first mapping one function over the functor and then mapping the other. So:

fmap (f . g) = fmap f . fmap g.

Huh? Well, fmap (f . g) (Just x) is (if you go back and look) defined as Just ((f . g) x), which is the same as Just (f (g x)), since we’re just composing functions.

And fmap f (fmap g (Just x)) is fmap f (Just (g x)) which is then Just (f (g x)), so we’re ok!


Functors in haskell

  • Now why do we care?

  • If we know that a type obeys both laws, we can make certain assumptions about how it will act.

  • If a type obeys the functor laws, we know that calling fmap on a value of that type will only map the function over it, nothing more. This leads to code that is more abstract and extensible.

  • All the Functor examples in Haskell obey these laws by default.


  • Login