I have been slowly working through some more Haskell with help from Tony.

- Quickly worked through the previous stuff we did to refresh my memory.
- Consider a simplified version of the Eq type class.
class Eq a where

The type variable

(==) :: a -> a -> Bool`a`

is polymorphic over types. Now consider the Functor type class.class Functor f where

Here we have an example of higher-order polymorphism, e.g.

fmap :: (a -> b) -> f a -> f b`f a`

,`f b`

. The type variables`a`

and`b`

are polymorphic over types as before, but`f`

is polymorphic over type constructors. Note that`f`

has kind`* -> *`

as it is applied to a single type variable in both cases. - The Maybe type constructor has kind
`* -> *`

. We have effectively already written the`Functor`

implementation, i.e. the`mmap`

function in the previous work.class Functor' f where

(<$>) :: (a -> b) -> f a -> f b

instance Functor' Maybe where

(<$>) = mmap - Observe that
`->`

is a type constructor with kind`* -> * -> *`

. Given two types`a`

and`b`

,`a->b`

is the type of functions mapping elements of type`a`

to elements of type`b`

.

We can't write a`Functor`

instance for the`->`

type constructor as their kinds are different. However we can partially apply a polymorphic type, lets call it`t`

which gives`((->) t)`

and has kind`* -> *`

. - Exercise: write an instance of
`Functor`

for functions:instance Functor' ((->) t) where

Looks a little nasty when you first see it. Its a bit easier if you write out the type signature with the type constructor applied.

(<$>) = error "todo"<$> :: (a -> b) -> ((->) t a) -> ((->) t b)

It is more obvious in infix form.<$> :: (a -> b) -> (t -> a) -> (t -> b)

Now it is fairly easy to come up with an implementation. - Exercise: just for fun, write a Monad instance:
class (Functor' m) => Monad' m where

Again writing out the type signatures helps.

flatMap :: (a -> m b) -> m a -> m b

pure :: a -> m a

instance Monad' ((->) t) where

flatMap = error "todo"

pure = error "todo" - Note the laws that all
`Functor`

instances should satisfy.fmap id == id

The combination of the

fmap (f . g) == fmap f . fmap g`Functor`

type class and these laws define a particular concept/pattern. Intuitively function composition and the traditional map function seem like very different things, yet they are both instances of this abstraction. - Exercise: write an implementation for:
(<***>) :: (Functor f, Functor g) => (a -> b) -> g (f a) -> g (f b)

It took me a while, with help, so the answer is at the bottom of the post.

This is all well and good, but what use is it? Here are two examples of using the

`<***>`

function.Example 1

data Connection = Connection

newtype Conn a = Conn {

conn :: Connection -> a

}

instance Functor Conn where

k `fmap` Conn z = Conn (k . z)

data ResultSet = ResultSet

data Person = Person

f :: ResultSet -> Person

f = undefined

executeQuery :: String -> Conn ResultSet

executeQuery = undefined

k :: String -> Conn Person

k = f <***> executeQuery

Example 2

g :: Maybe [Bool] -> Maybe [String]

g = (<***>) show

Useful references.

- A Gentle Introduction to Haskell: 2 Values, Types, and Other Goodies
- Functional Programming with Overloading and Higher-Order Polymorphism

Answer for 7.

(<***>) :: (Functor f, Functor g) => (a -> b) -> g (f a) -> g (f b)Or in point free form.

f <***> g = (f `fmap`) `fmap` g

(<***>) = fmap . fmap

## 1 comment:

(<***>) = fmap . fmap

Or for kicks:

(<***>) = fmap `fmap` fmap

Though it doesn't buy you anything ;)

Post a Comment