Created
May 6, 2014 09:13
-
-
Save adinapoli/7a8620e4f9ac277ed2f5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Sources: | |
-- http://www.haskellforall.com/2012/09/the-functor-design-pattern.html | |
-- http://www.haskell.org/haskellwiki/Functor | |
-- http://learnyouahaskell.com/functors-applicative-functors-and-monoids | |
-- Hide pre-existing Maybe and map function from Prelude. | |
import Prelude hiding (Maybe (..), map) | |
-- Import the Monadic composition operator. | |
import Control.Monad ((<=<)) | |
-- Definition: | |
-- A functor transforms one category into another category. | |
-- We define a custom maybe data type. What this says is that Maybe | |
-- has a type constructor 'a' and is a union type that is either | |
-- Just a or Nothing. | |
data Maybe a = Just a | Nothing deriving(Show, Eq) | |
-- We can make it an instance of the functor typeclass. To do this | |
-- we must define fmap on our Maybe data type. | |
instance Functor Maybe where | |
fmap f Nothing = Nothing | |
fmap f (Just x) = Just (f x) | |
-- The type signature of fmap is: | |
-- | |
-- fmap :: Functor f => (a -> b) -> f a -> f b | |
-- | |
-- It takes a function (a -> b) and unwraps the value inside the functor, | |
-- applies the function and then re-wraps the value into the functor. | |
-- Functors must satisfy the following laws in order to be correct. | |
-- fmap id = id | |
-- fmap (p . q) = (fmap p) . (fmap q) | |
-- What this says is that passing the identity function to fmap should be | |
-- equivalent to calling the identity function on the functor data type and | |
-- the second of the two means that it is closed under composition. | |
justOne = Just 1 | |
lawOne = fmap id justOne == id justOne | |
lawTwo = fmap ((* 2) . (* 3)) justOne == (fmap (* 2) . fmap (* 3)) justOne | |
-- Surprisingly, the Haskell world view of functors is really quite limited. | |
-- The functor type class focuses on the notion of functors as being | |
-- container types and the application of functions on them. | |
-- More generally, functors can be viewed as a mapping between two categories. | |
-- This could, for example, be the mapping between pure functions and monadic | |
-- functions. | |
-- Let's make our Maybe data type a Monad instance. Let's forget about the | |
-- details for now because we'll cover monads in week three. | |
instance Monad Maybe where | |
return x = Just x | |
val >>= f = case val of | |
Nothing -> Nothing | |
Just x -> f x | |
-- Here is our function that maps our pure function to the category of monadic | |
-- functions. | |
map :: (Monad m) => (a -> b) -> (a -> m b) | |
map f = return . f | |
-- An addition function in the category of pure functions. | |
pureAddOne :: Integer -> Integer | |
pureAddOne = (+ 1) | |
-- This allows us to write adapter functions that map our pure functions | |
-- into the category of monadic functions. | |
justTen = Just 10 | |
result = justTen >>= (map pureAddOne) | |
-- We can even prove it is a functor by checking that it obeys to functor laws. | |
lawOne' = (justTen >>= map id) == id justTen | |
lawTwo' = (justTen >>= map ((* 2) . (* 3))) == (justTen >>= (map (* 2) <=< map (* 3))) | |
-- Therefore, we can say that the map we defined is a functor. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment