Composition in purescript

By Thomas Bracher

Why composition?

  • Decompose problems in small solutions and recompose them into a software
  • Practical guide to purely functional language

"Simple" tutorial

appInit :: SnapletInit App App
appInit = makeSnaplet "myapp" "My example app" Nothing $ do
    hs <- nestSnaplet "heist" heist $ heistInit "templates"
    fs <- nestSnaplet "foo" foo $ fooInit
    bs <- nestSnaplet "" bar $ nameSnaplet "newname" $ barInit foo
    addRoutes [ ("hello", writeText "hello world")
              , ("fooname", with foo namePage)
              , ("barname", with bar namePage)
              , ("company", companyHandler)
              ]
    wrapSite (<|> heistServe)
    ref <- liftIO $ newIORef "fooCorp"
    return $ App hs fs bs ref

Source: snap tutorial

Discover Composition

  1. Functor: map
  2. Apply: apply
  3. Applicative: pure
  4. Bind: bind

Functor

map :: (a → b) → F a → F b

Length of a functor of strings

Integer length(String str) { ... }
Stream<String> names = Stream.of("Adil", "Aline");
Stream<Integer> nameLengths = names.map(::length);
length :: String → Integer
names :: List String
nameLengths :: List Integer
nameLengths = length <$> names

Other utilities of Functor

  • <$> map :: (a → b) → F a → F b
  • <#> mapFlip :: F a → (a → b) → F b
  • <@> flap :: F (a → b) -> a -> F b

Simple flap example

isLongEnough :: String → Boolean
hasSymbol :: String → Boolean
hasDigit :: String → Boolean
validate :: String → Array Boolean
validate input = [isLongEnough, hasSymbol, hasDigit] <@> input

Apply

"inherits" from Functor

<*> = apply :: F (a → b) → F a → F b

Usage of Apply

Date getDate(Day day, Month month) { ... }
Optional<Day> day = ...;
Month month = Month.July;
Optional<Date> date = day.map(day → getDate(day, month));

Note: Java does not provide tools like apply

Usage of Apply

getDate :: Day → Month → Date
maybeDay :: Maybe Day -- Just 1 | Nothing
month = July
getDate <$> maybeDay :: Maybe (Month → Date)
maybeDate :: Maybe Date
maybeDate = getDate <$> maybeDay <*> Just month

An idea on how to improve the last line?
(replacing the <*> with ...)

Other utility

lift2 :: (a → b → c) → F a → F b → F c

Applicative

"inherits" from Apply

pure :: a -> F a

Examples in Java

Optional<String> opt = Optional.of("hello");
Stream<String> str = Stream.of("hello");

Why are they not strictly Applicatives?

Same in Purescript

pure "hello" :: Maybe String
pure "hello" :: List String

Bind

"inherits" from Apply

>>= bind :: F a → (a → F b) → F b

Usage example of Bind

Optional<Date> parseDate(String str) { ... }
Optional<String> input = getInput();
Optional<Date> date = input.flatMap(str → parseDate(str));
parseDate :: String → Maybe Date
input = getInputFromUnknownSource :: Maybe String
maybeDate = input >>= parseDate
maybeDate = do
  input ← getInputFromUnknownSource
  parseDate input

Bind alternatives

  • =<< :: (a → F b) → F a → F b
  • >=> :: (a → F b) → (b → F c) → a → F c
  • join :: F (F a) → F a

Kleisli composition

parseDate :: String → Maybe Date
getSubscription :: Date → Maybe Subscription
getFare :: Subscription → Maybe Money
getFareFromDate input =
  (parseDate >=> getSubscription >=> getFare) input

Do you remember how we simplified this at the very beginning?

Monad

"inherits" from Bind and Applicative

[mind blowing gif]

Monad

  • map :: (a → b) → F a → F b
  • apply :: F (a → b) → F a → F b
  • pure :: a → F a
  • bind :: (a → F b) → F a → F b

What is a Monad?

  • List
  • Maybe
  • IO with monad Eff

A lot more

  • Comonad, Traversable, Monoid, etc.
  • A lot of different tools to compose
  • There's always a tool for what you're doing!

Functional languages are made for composition

Thank you

Resources