Applicative

Contents
Functions in a context
pure
Validation with lists
liftA2 and friends

Functions in a context

fmap applies a plain function to a wrapped value. Applicative goes one step further and applies a wrapped function:

class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b Just (+1) <*> Just 2 -- Just 3 [(*2), (+10)] <*> [1,2] -- [2,4,11,12]

The list case applies every function to every value, which is the cartesian product. That looks odd until you use it for validation in the next section.

pure

pure puts a plain value into the smallest possible context. For Maybe that is Just, for a list it is a one-element list:

pure 5 :: Maybe Int -- Just 5 pure 5 :: [Int] -- [5] pure (+) <*> Just 1 <*> Just 2 -- Just 3

The second line is the idiomatic way to combine two wrapped values with a plain function. Once you see it, liftA2 in the last section is just a name for the same idea.

Validation with lists

A list applicative collects every failure instead of stopping at the first. This is how a form reports three bad fields at once:

check :: Int -> [String] check n | n < 0 = ["too small"] | n > 100 = ["too big"] | otherwise = [] validate a b = (\_ _ -> ()) <$> check a <*> check b -- validate (-1) 200 == ["too small","too big"]

The same shape with Maybe stops at the first Nothing, because a Maybe has at most one failure to report. The container decides the strategy, not the calling code.

liftA2 and friends

The library names the common arities so that the operator soup disappears. All of them are defined with pure and <*>:

liftA2 (+) (Just 1) (Just 2) -- Just 3 liftA2 (+) Nothing (Just 2) -- Nothing sequenceA [Just 1, Just 2] -- Just [1,2] sequenceA [Just 1, Nothing] -- Nothing

sequenceA turns a list of containers into a container of a list, failing if any element fails. Lesson 44 generalises it to Traversable.

Next: Monad

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: