Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting Started with PureScript

Getting Started with PureScript

## Abstract

PureScript is a small, modern pure functional programming language that compiles to JavaScript. It is written in and inspired by Haskell, with an expressive static type system designed for natural, effortless interaction with existing JavaScript programs. In this gentle introduction to the PureScript programming language, we will examine its type system, syntax, idioms, and current best practices.

## Notes

View the rendered Markdown at https://gist.github.com/michaelficarra/4473c9901120f2ff87e0.

### Slide 1: Getting Started With PureScript

* Image credit: http://crowactive.com/wp-content/uploads/2010/05/crow6sm.jpg
* PureScript is a small functional programming language that compiles to -- and, more importantly, easily interfaces with -- JavaScript.
* We'll take a quick tour of the language and see what makes it special. Then, we'll see how we can start using it and learning about it in depth.

### Slide 2: Literals

* Functional programming languages are concerned with values. These are the values we use in PureScript. For those of you with a Haskell background, most of the syntax and many of the concepts will be pretty familiar, so bear with me. A notable difference to keep in mind is that PureScript is strict, whereas Haskell is lazy.
* We have a number (specifically a double), a string, a Boolean, an array, a record, and a function. These values are internally represented *and* exposed through FFI as the associated JavaScript value.
*...

Michael Ficarra

July 15, 2015
Tweet

More Decks by Michael Ficarra

Other Decks in Programming

Transcript

  1. Literals a = 0.0 :: Number b = "a" ::

    String c = true :: Boolean d = [0.0] :: Array Number e = {foo: 0.0} :: { foo :: Number } f = (\a -> a) :: forall a. a -> a
  2. Function Definition & Application sum :: Int -> Int ->

    Int sum a b = a + b successor :: Int -> Int successor = sum 1 sumSuccessors :: Int -> Int -> Int sumSuccessors a b = sum (successor a) (successor b) seven :: Int seven = sumSuccessors 2 3
  3. Function Definition (cont.) identity :: forall t. t -> t

    identity a = a const :: forall a b. a -> b -> a const x y = x ($) :: forall a b. (a -> b) -> a -> b ($) f x = f x infixr 0 $
  4. Records hank :: { name :: String, birthYear :: Int

    } hank = {name: "Hank", birthYear: 1985} laptop :: { name :: String, mfgDate :: Int } laptop = {name: "Hotaru", mfgDate: 2014} greet :: forall r. { name :: String | r } -> String greet namedThing = "Hello, " ++ namedThing.name hankJr :: { name :: String, birthYear :: Int } hankJr = hank { birthYear = 2010 }
  5. Algebraic Data Types data Ordering = Less | Equal |

    Greater compare :: Number -> Number -> Ordering compare a b = if a < b then Less else if a == b then Equal else Greater
  6. Algebraic Data Types (cont.) data List t = EmptyList |

    Cons t (List t) listA :: List Number listA = Cons 0.0 (Cons 1.0 (Cons 2.0 EmptyList)) listB :: List String listB = Cons "x" (Cons "y" EmptyList) listC :: forall a. List a listC = EmptyList
  7. Type Aliases type Option = Maybe type NumberArray = Array

    Number type NumberList = List Number type Point = { x :: Number, y :: Number } type Pair a b = { left :: a, right :: b } type Predicate a = a -> Boolean
  8. Pattern Matching data Maybe t = Nothing | Just t

    map :: forall a b. (a -> b) -> Maybe a -> Maybe b map f Nothing = Nothing map f (Just x) = Just (f x) map' f maybe = case maybe of Nothing -> Nothing (Just x) -> Just (f x)
  9. Pattern Matching (cont.) type Point = { x :: Number,

    y :: Number } doubleZero :: Point -> Point doubleZero p@{ x: 0, y: y } = p { y = y * 2.0 } doubleZero p = p const :: forall a b. a -> b -> a const x _ = x
  10. Program Structure module Namespace.ModuleName where import OtherNamespace.OtherModule data Type0 t

    = Constructor0 t | Constructor1 t t value0 = Constructor1 0 1 value1 = Constructor0 "string"
  11. Program Structure (cont.) module ModuleName (value0, main, Type0(..)) where import

    OtherModule (value1, Type1(..)) import qualified Prelude as P data Type0 t = Constructor0 t | Constructor1 t t value0 :: Type0 Int value0 = Constructor1 0 1 main :: Eff () Unit main = P.return P.unit
  12. Hello, World! module Main (main) where import Control.Monad.Eff (Eff(..)) import

    qualified Control.Monad.Eff.Console as Console main :: Eff (console :: Console.CONSOLE) Unit main = Console.log "Hello, World!"
  13. Effects module EffExample (main) where import Control.Monad.Eff (Eff(..)) import Control.Monad.Eff.Random

    (random, RANDOM()) -- random :: Eff (random :: RANDOM) Number import Control.Monad.Eff.Console (log, print, CONSOLE()) -- log :: String -> Eff (console :: CONSOLE) Unit -- print :: ... -> Eff (console :: CONSOLE) Unit main :: Eff (console :: CONSOLE, random :: RANDOM) Unit main = random >>= print
  14. Composing Effects main :: Eff (console :: CONSOLE, random ::

    Random) Unit main = do a <- random b <- random log "First random number:" print a log "Second random number:" print b
  15. Type Classes class Show a where show :: a ->

    String instance showBoolean :: Show Boolean where show true = "true" show false = "false" instance showArray :: (Show a) => Show (Array a) where show array = "[" <> map show array <> ]"
  16. JavaScript Interoperability (FFI) -- MyModule.purs foreign import parseFloat :: String

    -> Number foreign import pow :: Number -> Number -> Number // MyModule.js exports.parseFloat = parseFloat; exports.pow = function pow(base) { return function(exponent) { return Math.pow(base, exponent); }; };
  17. JavaScript Interoperability (cont.) foreign import data TimeoutID :: * foreign

    import data TIMER :: ! foreign import setTimeout :: forall e. Eff e Unit -> Number -> Eff (timer :: TIMER) TimeoutID foreign import clearTimeout :: TimeoutID -> Eff (timer :: TIMER) Unit
  18. Installation Precompiled Binaries https://github.com/purescript/purescript/releases/latest Cabal $ cabal update $ cabal

    install purescript Brew $ brew update $ brew install purescript npm $ npm install -g purescript
  19. Starting a Project Pulp $ npm install -g pulp $

    pulp init Yeoman with Gulp $ npm install -g yo generator-purescript bower $ yo purescript Do-It-Yourself $ mkdir -p src/Namespace/Namespace $ touch !$/ModuleName.purs
  20. Building Pulp $ pulp build Gulp $ gulp Do-It-Yourself $

    psc 'src/**/*.purs' --ffi 'src/**/*.js' \ 'bower_components/purescript-*/src/**/*.purs' \ --ffi 'bower_components/purescript-*/src/**/*.js' $ psc-bundle --module ModuleName --main ModuleName.Main \ 'output/**/*.js' > dist/ModuleName.js
  21. Managing Dependencies Install Bower $ npm install -g bower $

    bower init Install Dependencies $ bower install --save purescript-monoid $ bower install --save-dev purescript-quickcheck Publish $ git tag -a v1.0.0 -m 'Version 1.0.0' $ git push --tags $ bower register
  22. Testing module Test.Main (main) where import Test.QuickCheck (quickCheck) import Data.Array

    (sort, length) sortIsIdempotent :: Array Number -> Boolean sortIsIdempotent a = sort (sort a) == sort a sortPreservesLength :: Array Number -> Boolean sortPreservesLength a = length (sort a) == length a main = do quickCheck sortIsIdempotent quickCheck sortPreservesLength
  23. Testing (cont.) $ bower install --save-dev purescript-quickcheck ... $ pulp

    test * Building project in /path/to/purescript-arrays * Build successful. Running tests... 100/100 test(s) passed. 100/100 test(s) passed. * Tests OK.
  24. Unit Tests main = runNode [consoleReporter] do describe "Data.Array" do

    describe "range" do it "creates a range" do range 3 5 `shouldEqual` [3, 4, 5] range 1 100 `shouldContain` 50 describe "length" do it "calculates the length" do length [] `shouldEqual` 0 length [0] `shouldEqual` 1 length [[0, 0], [0, 0]] `shouldEqual` 2 describe "cons" do pending "cons tests"
  25. Big Changes in 0.7.x • (32-bit) Int type and integer

    literals • character literals • no more Prelude auto-import • no more [a] notation for Array types • no more (a:as) cons patterns • no more inline FFI • new typeclasses: Ring, Lattice, Bounded, Poset, ... • effects in PSCi • fix suggestions in error messages