High-level overview of PureScript
Tags: webdev, beginners, javascript, purescript
Published: 2023-10-25 01:48:00

I want to do a high-level overview of PureScript and its ecosystem. Who uses it and why? What are the trade-offs and shortcomings (especially for newcomers)? Want to sketch out a map of the ecosystem, resources, community, and so on.

---

📹 Hate reading articles? Check out [the complementary video](https://youtu.be/GTYgsXTh10Q ), which covers the same content.

## Blitz round

**Do people use PureScript in production?** Yes.

**Is PureScript just a Haskell for the frontend?** No. It’s pretty different, and you can also use PureScript on the backend.

**Why is PureScript not so popular then?** Probably because there is some learning curve to it, and nobody is pouring millions into its marketing.

**Is it better than TypeScript or Elm?** The languages have different [values](https://dev.to/zelenya/do-your-values-align-with-fp-values-48l9) and design goals — one can’t be purely better than another. You have to see what suits you better.

## Intro

Let’s talk about (currently) main pathways to PureScript: after some frontend experience or after some backend. 

> 🤔 What about PureScript as a first language? Probably not. Too many balls to juggle.
> 

- If you come from the FE, luckily, you can build on top of your knowledge — you can use most of your tools, bundlers, libraries, and even frameworks. You need to learn a new language (probably new syntax), new features, and (unless you’re coming from Elm, ClojureScript, or something along these lines) functional programming.
- If you come from the backend, you have some catching up to do (everything mentioned above). It’s going to be easier if you have an FP background. *And that’s where I came from, and honestly, after years of using PureScript, I still can’t wrap my head around all the bundlers and package managers, but I know what to copy-paste and search for.*

## Why, Where, and How of using PureScript

PureScript is a general-purpose programming language — you can use it in various domains.

- I used it on the backend in a typical microservice to shuffle data around.
- I used it on the frontend in a typical *React* single-page app/user-interface.

PureScript transpiles to JavaScript, Erlang, (soon) Chez Scheme, and others. And even if you limit yourself to JavaScript, you can put PureScript on top of [Node.js](https://nodejs.org/en) or something, boom, new runtime.

I don’t want to talk about random language features. It’s hard to sell a feature without talking about the particular problems to solve. So, I’ll just mention two things I genuinely love about PureScript and miss in other languages.

### Row Polymorphism

Whenever I have to manipulate data with other languages, I dream about using PureScript. Especially if you have to integrate with some legacy “REST” service with questionable data, which needs to be validated and transformed, their entities have lots of fields, which are sometimes reused and sometimes the same; some fields are optional here but required there…

When you have a statically typed language, you must write a lot of boilerplate to deal with all the differences and nuances in the data types. Annoying. When you have a dynamically typed one, you have to deal with type of data, optionality, and validations. Annoying.

Row Polymorphism is both — you keep the type-safety and still write pretty flexible/polymorphic/structural/dynamic/whatever-you-wanna-call-it/code. Let the example speak for itself:

```haskell
parseDate :: forall r. { updatedAt :: String | r } -> { updatedAt :: Maybe Date | r } 
parseDate anything = ... -- implementation doesn't matter
```

The `parseDate` function can be used with any entity (data type) with a field `updatedAt`; it tries to parse the date string as a proper date. And imagine, when you have many functions like this, you can combine them like lego blocks to deal with any data. It’s amazing.

```purescript
parseDate { message: "Is this october or november?", updatedAt: "2020/10/11" }

... parseCountryCode (parseDate { ..., countryCode: "NULL", updatedAt: "01/01/2023", ... })
```

> 🔌 Checkout [A joy of working with JSON using PureScript](https://www.youtube.com/watch?v=fXCYKqcX1Bc) on the topic
> 

### Community

My second favorite thing is not a language feature. It’s **Community**.

Not going to lie; PureScript is a fantastic community. It is welcoming to beginners, hardcore enthusiasts, and everyone in between.

The [PureScript Discourse](https://discourse.purescript.org/) and [PureScript Discord](https://purescript.org/chat) are both great places to ask questions (and answer them).

> 🙏 At this point, I feel the responsibility to ask: If you’re an asshole, please, go somewhere else; there’re a lot of languages that will welcome you
>

## Learning resources, books and docs

The **free** [PureScript By Example](https://book.purescript.org/) book contains several practical projects; it's a great resource for PureScript beginners.

Alternatively, you can start with the [Functional Programming Made Easier](https://leanpub.com/fp-made-easier) book, which takes you from zero Functional Programming knowledge to a Full-Stack web app written in PureScript.

You can also visit the PureScript [documentation repository](https://github.com/purescript/documentation) on GitHub to find articles, guides, in-depth learning resources for beginners, and more. For example, it links to [PureScript Cookbook](https://github.com/JordanMartinez/purescript-cookbook).

On top of that there are a few incredible personal resources, my personal favorites are [Thomas Honeyman Articles](https://thomashoneyman.com/articles/), [Mark’s alethic.art](https://alethic.art/getting-started/with-purescript), and [Jordan’s PureScript Reference](https://jordanmartinez.github.io/purescript-jordans-reference-site/)

## Tooling

PureScript comes with excellent tooling and editor support with instant rebuilds.

The recommended build tool for PureScript is [Spago](https://github.com/purescript/spago/blob/master/README.md).

When it comes to coding, you can use any of your favorite editors via [`purs ide`](https://github.com/purescript/purescript/tree/master/psc-ide) (an IDE server that comes with compiler) or [PureScript language server](https://github.com/nwolverson/purescript-language-server), which is built on top of it. 

> 💡 For details, see the dedicated documentation section on [Editor support](https://github.com/purescript/documentation/blob/master/ecosystem/Editor-and-tool-support.md).
> 

[Pursuit](https://pursuit.purescript.org/) is one of the coolest things. It hosts the API documentation and lets us search it by package, module, function names, and type signatures.

![Pursuit](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6py7baa6kd77hk7rbs6w.png)

There is also [purs-tidy](https://github.com/natefaubion/purescript-tidy) — a formatter for PureScript source code with pretty good defaults; there is no reason not to use it (*it comes from someone who worked on a couple of formatters*). 

> 💡 For more, see [Editor and tool support](https://github.com/purescript/documentation/blob/master/ecosystem/Editor-and-tool-support.md) and [Recommended Tooling for PureScript](https://discourse.purescript.org/t/recommended-tooling-for-purescript-in-2022/3206) series.
> 

### JavaScript-backend specific

If you import libraries from JavaScript, you need a **package manager**. You can use [npm](https://www.npmjs.com/) (commonly used), [yarn](https://yarnpkg.com/), or whatever.

You also need a **bundler** to deal with JavaScript imports, smoosh your files, etc. You can get started with [esbuild](https://esbuild.github.io/). The most popular alternatives are [webpack](https://webpack.js.org/) and [parcel](https://parceljs.org/), but you can probably make things work with whatever you prefer.

## PureScript on the frontend

*Speaking of frontend.* This is the last big topic we’ll cover because it’s not relevant to everyone. 

The most important thing to know is how to use JavaScript code (libraries) and integrate with JavaScript frameworks. tl;dr, it’s simple but boilerplate-y.

First, I want to emphasize that you can mix and match JavaScript, TypeScript, PureScript, and whatever code: you can keep your old code and implement new components using PureScript. Moreover, you can migrate one peace at a time — you don’t have to abandon what you have and do big rewrites. 


![frontend](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b4dakwt1p2bg0d6lvpkt.png)

That happened in one of my previous companies — JavaScript/TypeScript React code base over a couple of months turned into PureScript code base.

### Interoperability with JavaScript

*Also called The Foreign Function Interface or FFI for short.*

The simplest way to use JavaScript code from PureScript is to give a type to an existing JavaScript value using a *foreign import* declaration. Let’s take the `square` function for example:

```jsx
// JavaScript file
"use strict";

export const square = function (n) {
  return n * n;
};
```

```haskell
-- PureScript file
module Test where

foreign import square :: Number -> Number
```

```purescript
-- PureScript usage
import Test

square 5.0
```

There is no magic to it — we bridge the gap between the world by explicitly adding a type signature.

Note that functions in PureScript are **curried** and **don’t tolerate side-effects**. Both require learning and a bit of practice — but nothing to worry about. Here is a real-world example (we let the library do the work):

```jsx
// JavaScript side
export { default as reactPlayerImpl } from 'react-player';
```

```haskell
-- PureScript side
foreign import reactPlayerImpl
  :: ReactComponent { url :: String, light :: Maybe Boolean }
```

```haskell
-- PureScript usage
player1 :: JSX
player1 = reactPlayer { url: "https://youtu.be/tIUXB0TrlpU", light: Just true }
```

Note that we are explicit only about the types and things we actually care about — [react player](https://www.npmjs.com/package/react-player#props) accepts a bunch of other props, but we don’t care.

Calling PureScript function from JavaScript is straightforward as well. One thing to keep in mind is that PureScript functions become JavaScript functions *of a single argument:*

```haskell
-- PureScript file
module Test where

first :: Int -> Int -> Int
first a _ = a
```

```jsx
// JavaScript file
import { gcd } from 'Test';

first(10)(2);
```

> 💡 You can read more about interoperability in the [book](https://book.purescript.org/chapter10.html#the-foreign-function-interface), [docs](https://github.com/purescript/documentation/blob/master/guides/FFI.md), reference, or anywhere else.
> 

### Frameworks

At the moment, the most popular UI Frameworks in PureScript ecosystem are [Halogen](https://purescript-halogen.github.io/purescript-halogen/) and [React](https://react.dev/).

> 💡 Checkout [Real World Halogen](https://github.com/thomashoneyman/purescript-halogen-realworld) and [Real World PureScript React](https://github.com/jonasbuntinx/purescript-react-realworld), which demonstrate the same project using both frameworks.
> 

Halogen is a declarative, component-based UI library for PureScript that emphasizes type safety. You can try the following code [here](https://try.purescript.org/?code=LYewJgrgNgpgBAWQIYEsB2cDuALGAnGAKEJWAAcQ8AXOABQKgjCJPMpoFEAzLmAYxoAKbrwEBKVhWpwAEkiggA5jAxIAzrMntZ8pSoB0AQR5x1sw1ulyFytPpkAVBABlTGmTMs1reu45f6HABuKlQaZjIcXjo2BgBqACIgwPoJeCgheHCCeBBoAKoAkhKEwKgYAFwVcCL8NPloKFSl5XAAvOb6uWg%2BtsZccGAghHBwAEbgAJ5wADwAtJ1ImKhUAEJTI3DdRXB8yRRooXB5TeMbhGBIVEhwhgIoIBgdhWh8BMBHAD5wCfzvocQ9mxDmgaG1NjJ9MAANYAYX2jwBo1GAG84Ogmih5ABla5UIjIuAAGi2KmYeE2oxJMCC8mqkJhwXkcAAJLJ9MwuEhoFQmVA4GjsEg0GBYHcqA8nnAhSKxfdHnAAL6UpWbHD4AnoxoSnF4%2BAAfXacAADMRRgQRfg4Go9e0VR4ORl9SrRgBtWSQsYQKhUBXuyL6R6wqAoPjQuAAHUNcwAfD8-jAPqC4ABdOD%2ByH4gAeNAARHNc6mXcSPY6goaM-pszQ2WpsCBMNbbSniySHV6fX7ZBxA2hg6Hw1G4LG4C83omjmnK9W4LmANSFluE0YtzYy0UwcWSo18dQGuAgLgqsf-ZMjhngFBcSaGiM2q7wEf3-FwOdwACMKt%2B46TNHPUMva9b2fR84xA4cP2IIA):

```haskell
module Main where

import Prelude

import Effect (Effect)
import Halogen as H
import Halogen.Aff as HA
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Halogen.VDom.Driver (runUI)

main :: Effect Unit
main = HA.runHalogenAff do
  body <- HA.awaitBody
  runUI component unit body

data Action = Increment | Decrement

component =
  H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
    }
  where
  initialState _ = 0

  render state =
    HH.div_
      [ HH.button [ HE.onClick \_ -> Decrement ] [ HH.text "-" ]
      , HH.div_ [ HH.text $ show state ]
      , HH.button [ HE.onClick \_ -> Increment ] [ HH.text "+" ]
      ]

  handleAction = case _ of
    Increment -> H.modify_ \state -> state + 1
    Decrement -> H.modify_ \state -> state - 1
```

And React is React. There is a whole [react-basic](https://github.com/purescript-react) family of PureScript packages, which include basic components, specific components, starter applications, [Hooks API](https://github.com/purescript-react/purescript-react-basic-hooks), and so on.

---

What about other frameworks and libraries? It depends. If you’re lucky and somebody already done the work, you can use a PureScript wrapper-library and don’t worry about JavaScript. If not, then you have to do some prep work (how much depends on how rigid and highly coupled the library is).

> 💡 **Pro-tip:** Don’t forget to check with your friends on discord, if you can collaborate with someone.
> 

## Where to go from here

Where to go from here? 

- Get started with [PureScript website](https://www.purescript.org/) or [Getting Started Guide](https://github.com/purescript/documentation/blob/master/guides/Getting-Started.md).
- Start learning with free [PureScript By Example](https://book.purescript.org/) Book.
- Start talking on [PureScript Discord](https://purescript.org/chat) server.
- Start playing with PureScript at [try.purescript.org](https://try.purescript.org/)

Last winter, together with a two sets of my ex-colleagues, we shared our experiences of using [PureScript in production](https://dev.to/zelenya/purescript-in-production-oc8).

And last but not least, go build some stuff.

### References and links

- [PureScript By Example](https://book.purescript.org/)
- [PureScript Discourse](https://discourse.purescript.org/) instance
- [Functional Programming Made Easier](https://leanpub.com/fp-made-easier)
- [PureScript: Cookbook](https://github.com/JordanMartinez/purescript-cookbook)
- [Thomas Honeyman Articles](https://thomashoneyman.com/articles/)
- [PureScript: Jordan’s Reference](https://jordanmartinez.github.io/purescript-jordans-reference-site/)
- [Mark’s alethic.art](https://alethic.art/getting-started/with-purescript)
- [Pursuit](https://pursuit.purescript.org/)

--- 

{% embed https://youtu.be/GTYgsXTh10Q  %}