Purescript, des sensations pures

I'm online!

n :: Person -> V Errors Person
validatePerson (Person o) =
  person <$> (nonEmpty "First Name" o.firstName *>
              pure o.firstName)
         <*> (nonEmpty "Last Name"  o.lastName  *>
              pure o.lastName)
           <*> validateAddress o.address
         <*> (arrayNonEmpty "Phone Numbers" o.phones *>
              traverse validatePhoneNumber o.phones)

« JS is terrible » blah blah

all the shortcomings of JS: - dynamic typing - suprising scoping - all the wat things

« Haskell is awesome » blah blah

- great type system - simple modelling with ADTs - type classes

purescript /= haskell

- strict - no runtime system - extensible effects - ghcjs / uhc with JS backend - simple FFI

Why not elm?

- general purpose - more powerful than elm (more complex as well) - optimized for correctness

What it looks like

module Main where

import Prelude
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)

main :: forall e. Eff (console :: CONSOLE | e) Unit
main = do
  log "Hello sailor!"

- pulp run - pulp browserify & open index

type Entry =
  { firstName :: String
  , lastName  :: String
  , address   :: Address
  }
showEntry entry = entry.lastName <> ", " <>
                  entry.firstName <> ": " <>
                  showAddress entry.address
factors :: Int -> Array (Array Int)
factors n = do
  i <- 1 .. n
  j <- i .. n
  guard $ i * j == n
  pure [i, j]

Cool features

Algebraic Data Types

type Entry =
  { firstName :: String
  , lastName  :: String
  , address   :: Address
  }

data RealEntryOrDummy =
    RealEntry Entry 
  | DummyEntry 
showEntryOrDummy :: RealEntryOrDummy -> String
showEntryOrDummy (RealEntry e) = e.firstname
showEntryOrDummy DummyEntry    = "Dummy Entry"

No standard lib

Currying

add x y = x + y

add5 = add 5

Typeclasses

class Show a where
  show :: a -> String

instance sreod :: Show RealEntryOrDummy where
  show = showEntryOrDummy

Extensible effects

main :: Eff (console :: CONSOLE, random :: RANDOM) Unit
main = do
  n <- random
  print n

FFI

"use strict";

exports.encodeURIComponent = encodeURIComponent;
module Data.URI where

foreign import encodeURIComponent :: String -> String

Type holes

results :: Array String
results = map ?test [1, 2, 3]

Tooling / getting started

bower for dependencies

pulp for building

pulp init
pulp run
pulp browserify

 But you can use webpack

pursuit

Halogen

Components

editor workout =
  H.component
    { initialState: const $ myInitialState
    , render
    , eval
    , receiver: const Nothing
    }
render :: EditorState -> H.ComponentHTML EditorQuery
render state = HH.div_ $
  map renderExerciseBlock state.workout.results
eval :: EditorQuery ~> H.ComponentDSL EditorState EditorQuery EditorMessage m
eval (Save next) = ?saveFunction
eval (UpdateBodyWeight value next) = ?updateWeight
eval (UpdateResultCounter exerciseIndex counterIndex next) = ?updateCounter
type ComponentSpec h s f i o m =
  { initialState :: i -> s
  , render :: s -> h Void (f Unit)
  , eval :: f ~> ComponentDSL s f o m
  , receiver :: i -> Maybe (f Unit)
  }
h is the type of value that will be rendered by the component.
s is the component's state type.
f is the component's query algebra.
i is the type for the component's input values.
o is the type for the component's output messages.
m is a monad used for non-component-state effects

Pux

Try Clever Cloud

I'm online!