Skip to content

Haskell Applicatives Guide — Applicative Typeclass and Effectful Programming

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Haskell Applicatives Guide. We cover key concepts, practical examples, and best practices to help you master this topic.

Haskell Applicative typeclass has pure (wrap a value) and <*> (apply wrapped function to wrapped value) -- enabling multiple independent effectful computations to be combined in a functional style.

Applicative Typeclass

class Functor f => Applicative f where
    pure  :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

-- Laws:
-- pure id <*> v = v
-- pure (.) <*> u <*> v <*> w = u <*> (v <*> w)

Maybe Applicative

-- All Just: applies the function
pure (+3) <*> Just 7      -- Just 10
-- Or:
Just (+3) <*> Just 7      -- Just 10

-- Multiple arguments
pure (+) <*> Just 3 <*> Just 4      -- Just 7
pure (\x y z -> x+y+z) <*> Just 1 <*> Just 2 <*> Just 3
-- Just 6

-- Any Nothing: result is Nothing
Just (+) <*> Nothing <*> Just 5     -- Nothing

List Applicative

-- Multiple functions applied to multiple values
pure (*2) <*> [1,2,3]     -- [2,4,6]

-- Cartesian product of functions and values
[(*2), (+1)] <*> [1,2,3]  -- [2,4,6,2,3,4]

-- liftA2
import Control.Applicative
liftA2 (+) [1,2] [10,20]  -- [11,21,12,22]

IO Applicative

-- Combine independent IO actions
greeting = pure (\greet name -> greet ++ " " ++ name)
    <*> getLine <*> getLine
-- Reads two lines, returns combined

-- Using liftA2
sumTwo = liftA2 (\a b -> read a + read b) getLine getLine

-- Sequential with (<*)
readAndPrint = putStrLn "Enter name:" <* getLine

Alternative Typeclass

-- Alternative provides (<|>) for choice
import Control.Applicative

-- Maybe: first Just wins
Just 3 <|> Nothing        -- Just 3
Nothing <|> Just 5        -- Just 5
Nothing <|> Nothing       -- Nothing

-- List: concatenation
[1,2] <|> [3,4]           -- [1,2,3,4]
empty <|> [1]             -- [1]

Common Mistakes

1. Using <*> where fmap works

When the function is pure (not wrapped), use fmap or <$>: (+3) <$> Just 5 not pure (+3) <*> Just 5.

2. Arguments out of order

<*> is left-associative. pure f <*> a <*> b applies f to a and b, not the other way.

3. Confusing Applicative with Monad

Applicative must run all effects. Monad can skip effects based on previous results.

Practice Questions

1. What does Just (2) <> Just 5 return? Just 10. The wrapped function is applied to the wrapped value.

2. What is liftA2? liftA2 f a b = pure f <*> a <*> b -- applies a binary function inside an Applicative.

3. What does (<|>) do for Maybe? Returns the first Just value, or Nothing if both are Nothing. Used for fallback logic.

FAQ

{{< faq question="What is the difference between Applicative and Monad?" >}} Applicative runs all effects independently then combines. Monad lets later effects depend on earlier results. Applicative is less powerful but more parallel-friendly. {{< /faq >}}

{{< faq question="What does pure do?" >}} Lifts a value into the applicative context: pure 5 :: Maybe Int gives Just 5, pure 5 :: [Int] gives [5]. {{< /faq >}}

{{< faq question="What is ZipList?" >}} ZipList is an Applicative for lists that zips instead of cartesian product: ZipList [(+1),(*2)] <*> ZipList [1,2] = ZipList [2,4]. {{< /faq >}}

What's Next

Now learn about monads.

Topic Description Link
Monads Monads and do notation {{< ref "11-monads" >}}
IO Input/output in Haskell {{< ref "12-io" >}}

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro