Haskell Applicative Laws
Applicative laws are equalities that every correct Applicative must satisfy. They state how pure and apply must behave for every wrapped value.
Identity and homomorphism hold
Identity leaves a value alone and homomorphism keeps pure values honest. Both checks print True.
main :: IO ()
main = do
print ((pure id <*> Just 3) == Just 3)
print ((pure (+1) <*> pure 3) == (pure 4 :: Maybe Int))Interchange swaps sides safely
Interchange swaps which side holds the pure value. The result stays the same.
main :: IO ()
main = do
print ((Just (+1) <*> pure 3) == (pure ($ 3) <*> Just (+1)))Composition agrees in both forms
Composition chains two wrapped functions before applying them. The staged form and the nested form agree.
main :: IO ()
main = do
print ((pure (.) <*> Just (+1) <*> Just (*2) <*> Just 3) == (Just (+1) <*> (Just (*2) <*> Just 3)))Example
main :: IO ()
main = do
print ((pure id <*> Just 3) == Just 3)
print ((pure (+1) <*> pure 3) == (pure 4 :: Maybe Int))
print ((Just (+1) <*> pure 3) == (pure ($ 3) <*> Just (+1)))
print ((pure (.) <*> Just (+1) <*> Just (*2) <*> Just 3) == (Just (+1) <*> (Just (*2) <*> Just 3)))Key points
- Identity: pure id applied to a wrapped value leaves that value unchanged.
- Homomorphism: applying a pure function to a pure value equals the pure result of that function.
- Interchange: a wrapped function applied to a pure value can swap sides without changing the result.
- Composition: pure composition applied in stages equals applying the functions in nested order.
- Checking laws: each law can be checked by printing whether its two sides are equal.
In this example, the first line checks identity, the second line checks homomorphism, the third line checks interchange, and the fourth line checks composition.
Note
laws are promises about behaviour and not extra operations to call in ordinary code.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Haskell Playground
Exercise
Which equality states the identity law for Applicative?