Learn Purescript in Y minutes

Want to discuss the content of this article? Join the conversation on Twitter!

Purescript… that’s another one of those compile-to-JS languages, right?

Purescript is a small strongly, statically typed language compiling to Javascript that I’ve been playing around with lately.

In the same vein as the website http://learnxinyminutes.com I have, while tinkering, compiled a fast, short and incomplete introduction to Purescript.

--
-- 1. Primitive datatypes that corresponds to their Javascript
-- equivalents at runtime.

-- Numbers
1 + 7*5 :: Number -- 36
-- Types are inferred, so the following works fine
9 / 2.5 + 4.4 -- 8
-- Hexadecimal literals
0xff + 1 -- 256
-- Unary negation
6 * -3 -- -18
6 * negate 3 -- -18
-- Modulus
3 % 2 -- 1
4 % 2 -- 0
-- Inspect the type of an expression in psci
:t 9 / 2.5 + 4.4 -- Prim.Number

-- Booleans
true :: Boolean -- true
false :: Boolean -- false
-- Negation
not true --false
23 == 23 -- true
1 /= 4 -- true
1 >= 4 -- false
-- Comparisions < <= > >=
-- are defined in terms of compare
compare 1 2 -- LT
compare 2 2 -- EQ
compare 3 2 -- GT
-- Conjunction and Disjunction
true && (9 >= 19 || 1 < 2) -- true

-- Strings
"Hellow" :: String -- "Hellow"
-- Multiline string
"Hellow\
\orld" -- "Helloworld"
-- Concatenate
"such " ++ "amaze" -- "such amaze"

--
-- 2. Arrays are Javascript arrays, but must be homogeneous

[1,1,2,3,5,8] :: [Number] -- [1,1,2,3,5,8]
[true, true, false] :: [Boolean] -- [true,true,false]
-- [1,2, true, "false"] won't work
-- `Cannot unify Prim.Number with Prim.Boolean`
-- Cons (prepend)
1 : [2,4,3] -- [1,2,4,3]

-- Requires purescript-arrays (Data.Array)
-- and purescript-maybe (Data.Maybe)

-- Safe access return Maybe a
head [1,2,3] -- Just (1)
tail [3,2,1] -- Just ([2,1]) 
init [1,2,3] -- Just ([1,2])
last [3,2,1] -- Just (1)
-- Random access - indexing
[3,4,5,6,7] !! 2 -- Just (5)
-- Range 
1..5 -- [1,2,3,4,5]
length [2,2,2] -- 3
drop 3 [5,4,3,2,1] -- [2,1]
take 3 [5,4,3,2,1] -- [5,4,3]
append [1,2,3] [4,5,6] -- [1,2,3,4,5,6]

--
-- 3. Records are Javascript objects, with zero or more fields, which
-- can have different types
let book = {title: "Foucault's pendulum", author: "Umberto Eco"}
-- Access properties
book.title -- "Foucault's pendulum"

getTitle b = b.title
-- Works on all records with a title (but doesn't require any other field)
getTitle book -- "Foucault's pendulum"
getTitle {title: "Weekend in Monaco", artist: "The Rippingtons"} -- "Weekend in Monaco"
-- Update a record
changeTitle b t = b {title = t}
changeTitle book "Ill nome della rosa" -- {title: "Ill nome della
  -- rosa", author: "Umberto Eco"}

--
-- 4. Functions
sumOfSquares x y = x*x+y*y
sumOfSquares 3 4 -- 25
-- In psci you have to write `let` in front of the function to get a
-- top level binding
mod x y = x % y
mod 3 2 -- 1
-- Infix application of function
3 `mod` 2 -- 1

-- function application have higher precedence than all other
-- operators
sumOfSquares 3 4 * sumOfSquares 4 5 -- 1025

-- Conditional
abs' n = if n>=0 then n else -n
abs' (-3) -- 3

-- Guarded equations
abs n | n >= 0    = n
      | otherwise = -n

-- Pattern matching

-- Note the type signature, input is an array of numbers The pattern
-- matching destructures and binds the array into parts
first :: [Number] -> Number
first (x:_) = x
first [3,4,5] -- 3
second :: [Number] -> Number
second (_:y:_) = y 
second [3,4,5] -- 4
sumTwo :: [Number] -> [Number]
sumTwo (x:y:rest) = (x+y) : rest 
sumTwo [2,3,4,5,6] -- [5,4,5,6]

-- sumTwo doesn't handle when the array is empty or just have one
-- element in which case you get an error
sumTwo [1] -- Failed pattern match

-- Complementing patterns to match
-- Good ol' Fibonacci
fib 1 = 1
fib 2 = 2
fib x = fib (x-1) + fib (x-2)
fib 10 -- 89

-- Use underscore to match any, where you don't care about the binding name
isZero 0 = true
isZero _ = false

-- Pattern matching on records
ecoTitle {author = "Umberto Eco", title = t} = Just t
ecoTitle _ = Nothing

ecoTitle book -- Just ("Foucault's pendulum")
ecoTitle {title: "The Quantum Thief", author: "Hannu Rajaniemi"} -- Nothing
-- ecoTitle requires both field to type check:
ecoTitle {title: "The Quantum Thief"} -- Object does not have property author

-- Lambda expressions
(\x -> x*x) 3 -- 9
(\x y -> x*x + y*y) 4 5 -- 41 
sqr = \x -> x*x

-- Currying
add x y = x + y -- is equivalent with
add = \x -> (\y -> x+y)
add3 = add 3
:t add3 -- Prim.Number -> Prim.Number

-- Forward and backward function composition
-- drop 3 followed by taking 5
(drop 3 >>> take 5) (1..20) -- [4,5,6,7,8]
-- take 5 followed by dropping 3
(drop 3 <<< take 5) (1..20) -- [4,5]

-- Operations using higher order functions
even x = x % 2 == 0
filter even (1..10) -- [2,4,6,8,10]
map (\x -> x+11) (1..5) -- [12,13,14,15,16]

-- Requires purescript-foldable-traversabe (Data.Foldable)

foldr (+) 0 (1..10) -- 55
sum (1..10) -- 55
product (1..10) -- 3628800

-- Testing with predicate 
any even [1,2,3] -- true
all even [1,2,3] -- false

If you liked this article, let me know! Send me an email or follow me on Twitter @lexicallyscoped.


←  Go Back