Haskell Functors Guide — fmap, (<$>), and the Functor Typeclass
In this tutorial, you will learn about Haskell Functors Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Haskell Functor is a typeclass with fmap (or infix <$>) that applies a function to a value wrapped in a context -- enabling map-like operations on Maybe, Either, lists, IO, and any type with a lawful fmap implementation.
Functor Typeclass
class Functor f where
fmap :: (a -> b) -> f a -> f b
-- (<$>) = fmap as infix operator
-- Laws:
-- fmap id = id
-- fmap (f . g) = fmap f . fmap g
Maybe and Either
-- Maybe Functor
fmap (*2) (Just 5) -- Just 10
fmap (*2) Nothing -- Nothing
(*2) <$> Just 5 -- Just 10
-- Either Functor
fmap length (Right "hello") -- Right 5
fmap length (Left "error") -- Left "error"
-- Chaining
process = fmap (+1) . fmap (*2)
process (Just 5) -- Just 11
List Functor
-- Lists are Functors
fmap (*2) [1,2,3] -- [2,4,6] (same as map)
-- Function composition with lists
process = fmap (+1) . fmap (*2)
process [1,2,3] -- [3,5,7]
-- Nested functors
fmap (fmap (*2)) [[1,2],[3]] -- [[2,4],[6]]
IO Functor
-- IO is a Functor
getLength = fmap length getLine
-- Or:
getLength = length <$> getLine
-- Combining IO and pure
greet = do
name <- fmap (++ "!") getLine
putStrLn $ "Hello, " ++ name
-- (++) "Hello," <$> getLine
Custom Functor
data Box a = Box a deriving Show
instance Functor Box where
fmap f (Box x) = Box (f x)
fmap (*3) (Box 10) -- Box 30
-- Tree Functor
data Tree a = Leaf a | Branch (Tree a) (Tree a)
instance Functor Tree where
fmap f (Leaf x) = Leaf (f x)
fmap f (Branch l r) = Branch (fmap f l) (fmap f r)
Common Mistakes
1. Expecting fmap to work on non-Functor types
fmap only works on types that implement the Functor typeclass. Lists, Maybe, Either, IO all do.
2. Violating Functor laws
fmap id must equal id. fmap (f . g) must equal fmap f . fmap g. Breaking these causes confusing behavior.
3. Confusing fmap with bind (>>=)
fmap applies a pure function. bind (>>=) applies a function that returns a monadic value.
Practice Questions
1. What does fmap (+1) (Just 5) return?
Just 6. fmap applies the function inside the Maybe context.
2. What is the infix version of fmap?
(<$>). (+1) <$> Just 5 is equivalent to fmap (+1) (Just 5).
3. Can IO be a Functor?
Yes. fmap length getLine returns an IO Int that reads a line and returns its length.
FAQ
{{< faq question="What are the Functor laws?" >}}
Identity: fmap id = id. Composition: fmap (f . g) = fmap f . fmap g. These ensure fmap behaves predictably.
{{< /faq >}}
{{< faq question="Is fmap for lists the same as map?" >}}
Yes, fmap on lists is exactly map. In fact, map = fmap for historical reasons.
{{< /faq >}}
{{< faq question="What is the difference between Functor and Applicative?" >}} Functor applies a pure function to a wrapped value. Applicative applies a wrapped function to a wrapped value. {{< /faq >}}
What's Next
Now learn about applicative functors.
| Topic | Description | Link |
|---|---|---|
| Applicatives | Applicative functors | {{< ref "10-applicatives" >}} |
| Monads | Monads and do notation | {{< ref "11-monads" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro