Applicative

Usage

  • Lift any value/function/etc. into a box-like type, f
  • Parallel Computation: Do all three simultaneously: X, Y, and Z.

(Note: Javascript is currently single-threaded, so this isn't entirely true. If it gets multi-thread support, that will change.)

Definition

See its docs: Applicative

class (Apply f) <= Applicative f where
  pure :: forall a. a -> f a

data Box a = Box a

instance Functor Box where
  map :: forall a b.       (a -> b) -> Box a -> Box  b
  map                       f         (Box a) = Box (f a)

instance Apply Box where
  apply :: forall a b. Box (a -> b) -> Box a -> Box  b
  apply               (Box  f     )   (Box a) = Box (f a)

instance Applicative Box where
  pure :: forall a. a -> Box a
  pure              a =  Box a

Laws

Identity

Definition: (pure (\x -> x) <*> v == v)

-- Start: 'v' == (Box 4)
(pure (\x -> x)) <*> (Box 4)
-- Replace pure call signature with body
( Box (\x -> x)) <*> (Box 4)
-- De-infix <*> to apply
apply (Box (\x -> x)) (Box 4)
-- Replace apply call signature with body
Box (\x -> x) 4)
-- Apply argument by replacing all 'x' with '4'
Box (\4 -> 4)  )
-- Keep body of function
Box (      4)  )
-- Remove whitespace and parenthesis
Box 4
-- Check law
(Box 4) == (Box 4)
-- Law met!
true

Composition

Definition: pure (<<<) <*> f <*> g <*> h == f <*> (g <*> h)

TODO: prove the above law using Box (a lot of work, so ignoring for now...)

Homomorphism

Definition: (pure f) <*> (pure x) == pure (f x)

TODO: prove the above law using Box (a lot of work, so ignoring for now...)

Interchange

Definition: u <*> (pure y) == (pure (_ $ y)) <*> u

TODO: prove the above law using Box (a lot of work, so ignoring for now...)

Derived Functions

  • Define an instance of Apply and Applicative and you get a Functor implementation for free!: liftA1
  • Do a computation...
    • if some condition is true: when
    • if some condition is false: unless

Note: when/unless is strict. For a lazy version, see purescript-call-by-name