A functor maps a function over values while preserving the surrounding data structure. Lists, Maybe values, and domain-specific types can therefore share mapping operations. section 1.3.3 section 6.3.3
Functor behavior appears through a common mapping interface:
- Mapping can change element types without changing the container structure, such as converting [Int] to [String]. section 6.3.3
- The fmap operation generalizes list mapping and replaces a simple loop for functional traversal. section 6.3.3
- Nested functors can be mapped with nested fmap, preserving both layers while transforming their contents. section 1.3.3
Mapping optional values
For [Maybe String], fmap (fmap length) produces [Maybe Int]. Just values become lengths, while Nothing remains Nothing. The outer fmap traverses the list; the inner fmap traverses each Maybe. section 1.3.3
A domain-specific instance
A custom SandwichConstructor type can implement fmap by composing the supplied function with each continuation. Its constructors and stored data remain intact while the continuation result changes. section 6.3.3
import Data.Functor (fmap) -- fmap :: (a -> b) -> [a] -> [b] #1 names :: [String] #2 names = ["Alice","Bob", "Trudy"] lengths :: [Int] #3 lengths = fmap length names #4 -- lengths: [5,3,5]
A compact list example shows fmap changing names into lengths while retaining list structure. section 1.3.3
Listing 6.3 Functor instance for the free monad
instance Functor SandwichConstructor where #1
fmap f (StartNewSandwich breadType component next) #2
= StartNewSandwich breadType component (f . next)
fmap f (AddComponent component sandwichBody next)
= AddComponent component sandwichBody (f . next)
fmap f (FinishSandwich mbBreadType sandwichBody next)
= FinishSandwich mbBreadType sandwichBody (f . next)
A custom instance demonstrates how mapping preserves domain constructors and transforms nested continuations. section 6.3.3





