liveBook · Manning

Fmap

As explained in Learn Haskell by Example

fmap is the standard Haskell function that applies a function to the contents of a value in a Functor while preserving the surrounding structure.

`fmap` applies a function to a value held inside a `Functor`, preserving the surrounding shape. Its general type is `Functor f => (a -> b) -> f a -> f b`: transform the inner `a` into `b`, while `f` remains unchanged. The infix spelling, `<$>`, is often easier to read in pipelines. section 8.2.3 section 8.5

Lists, `Maybe`, `Either`, and `IO` can all be mapped, but they keep their structure. Mapping over a list gives a list; mapping over `Maybe` gives `Maybe`; mapping over an `IO` action gives another `IO` action. A plain type such as `Int` cannot be a `Functor` because it has no type parameter in which to hold a mappable value. section 8.2.3 section 8.4

Convert command-line arguments inside IO

`getArgs` produces `IO [String]`, but an application may want `IO [Text]`. Rather than unpacking the action with `do`, map `T.pack` over its eventual list result: getArguments :: IO [T.Text] getArguments = map T.pack <$> getArgs The conversion changes each `String`; it does not run or remove the `IO` action. section 8.4

Keep CSV parse failures intact

A CSV parser can use `<$>` to construct a `Csv` only when `parseColumns` succeeds. Because `Either` maps its successful `Right` value, an error `Left` passes through unchanged. This lets parsing stages add structure without manually handling every failure at that point. section 8.2.2

Transform a parser result

A parser for the text `"P1"` can become a parser for `P1` with `fmap (const P1)`. The parser still consumes input and can still fail; only its successful parsed value changes. For a constant replacement, `<$` provides a shorter form: magicNumberP1P = P1 <$ string "P1" section 12.1.2

When implementing `fmap` for a custom container, map only the value the container exposes as its result:

  • For `Parser`, map through the `Either` result and then through the tuple’s second component, leaving errors and remaining input unchanged. section 12.1.2
  • For `RandomIO`, implement a `Functor` instance so a function modifies generated values while retaining the generator wrapper. section 9.1.6
ghci> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
ghci> :i fmap
type Functor :: (* -> *) -> Constraint
class Functor f where
  fmap :: (a -> b) -> f a -> f b

Inspect the type of `fmap` and the `Functor` class in GHCi to see exactly which type parameter is transformed and which wrapper is preserved. section 8.2.3

How Learn Haskell by Example covers it

How deep it goes
Defines the Functor type and kinds, then implements a `Parser` instance through nested `Either` and tuple mappings.
Examples
Demonstrates CSV construction, `String`-to-`Text` command arguments, magic-number parsers, and a proposed `RandomIO` Functor instance.
What it assumes
Builds from list `map` and `Maybe`, then introduces Functor constraints and kinds needed to understand eligible type constructors.
What you can do after
Apply it via `fmap`, `<$>`, and `<$` to transform successful or produced values while preserving their wrapper.
How it connects
Connects `fmap` to Functor, `map`, `Maybe`, `Either`, `IO`, kinds, Parser, `<$>`, and `<$`.

Also explained in

Compare how 3 books explain fmap →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.