The VikiD Truth

Knowledge base / Computing

Read This! | | Quick Links | Algorithms | AssemblyLanguage | BASH | C-Programmming | CommonLisp | Computer Security | Databases | Emacs | Exploitation | Functional Programming | Firewalls | Git | Haskell | Javascript | Julia | Social Engineering | Picolisp | Pharo Smalltalk | Purescript | Linux | Python | Operating Systems | Machine Learning | Metasploit | Open Data Science | Networking | Machine Learning | Racket | Scheme | Unity | vim | V | Web Development | Windows WSL

Purescript

Here is the truth about PureScript: it’s Haskell’s ideas, aimed at the places JavaScript runs. You get strong static types, purity and type classes, and out comes small, readable JavaScript.

What it is, in plain words

PureScript is a strictly evaluated, purely functional programming language that compiles to JavaScript (by default) and, through community backends, to other targets such as Erlang, Go, Lua, Python and Chez Scheme. It was created by Phil Freeman in 2013 and is now maintained by a core team and community. The compiler itself is written in Haskell.

Key features:

Why it matters

JavaScript (and even TypeScript) lets whole classes of bugs through: undefined is not a function, missing cases, mutation from afar. PureScript removes them by design. If it compiles, a surprising amount of the time it simply works – and refactoring a large front end becomes something you do calmly rather than fearfully. It’s also one of the gentlest on-ramps to typed functional programming for web developers, and the ideas carry straight back into Haskell.

An everyday analogy: an electrical inspector

TypeScript is a friendly electrician who checks the obvious things. PureScript is the full building inspector: every circuit, every junction box, and a stamp on any wire that touches the outside world (“this one has effects”). It’s slower to get approval, but once the stamp’s on the wall the house doesn’t catch fire.

flowchart LR
  P[".purs source"] --> C["purs compiler"]
  C --> J["ES modules in output/"]
  J --> B["esbuild / Vite bundle"]
  B --> W["Browser or Node.js"]
  C -. "alternate backends" .-> O["Erlang, Go, Lua, Python..."]

A hands-on example

You need Node.js. Install the compiler and the package manager/build tool Spago:

npm install -g purescript spago
mkdir hello-ps && cd hello-ps
spago init
spago run

Edit src/Main.purs:

module Main where

import Prelude
import Data.Array (filter, range)
import Data.Foldable (sum)
import Effect (Effect)
import Effect.Console (log)

-- A pure function: types say exactly what it does
squareSum :: Int -> Int
squareSum n = sum (map (\x -> x * x) (filter even (range 1 n)))

-- Row polymorphism: works on ANY record that has a `name` field
greet :: forall r. { name :: String | r } -> String
greet person = "Hello, " <> person.name

-- Algebraic data type with exhaustive pattern matching
data Shape = Circle Number | Rect Number Number

area :: Shape -> Number
area (Circle r) = 3.14159 * r * r
area (Rect w h) = w * h

main :: Effect Unit
main = do
  log (show (squareSum 10))                         -- 220
  log (greet { name: "Vikid", os: "Void Linux" })   -- extra field is fine
  log (show (area (Rect 3.0 4.0)))                  -- 12.0

spago run compiles and runs it on Node. If you add a new Shape constructor and forget to handle it in area, the compiler refuses to build – that’s the inspector at work.

For web apps the popular libraries are Halogen (component framework), Deku and react-basic bindings. Calling existing JavaScript goes through the FFI: write a Main.js file next to Main.purs, export functions, and declare their types with foreign import.

PureScript versus its neighbours

TypeScriptPureScriptElmHaskell
Typesgradual, unsound by designsound, inferredsound, inferredsound, inferred
Effects trackednoyes (Effect)managed by runtimeyes (IO)
Type classesnoyesnoyes
Evaluationstrictstrictstrictlazy
JS interopseamlessFFIports (restricted)via GHC JS backend

Common misconceptions

Connections

Purescript by Example

Last edited · 1 revisions

Tags: #Computing