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, 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 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 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:
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.
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 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Ā andĀ PureScript DiscordĀ 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Ā book contains several practical projects; it's a great resource for PureScript beginners.
Alternatively, you can start with the Functional Programming 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Ā on GitHub to find articles, guides, in-depth learning resources for beginners, and more. For example, it links to PureScript Cookbook.
On top of that there are a few incredible personal resources, my personal favorites are Thomas Honeyman Articles, Markās alethic.art, and Jordanās PureScript Reference
Tooling
PureScript comes with excellent tooling and editor support with instant rebuilds.
The recommended build tool for PureScript isĀ Spago.
When it comes to coding, you can use any of your favorite editors via purs ide
(an IDE server that comes with compiler) or PureScript language server, which is built on top of it.
š”Ā For details, see the dedicated documentation section on Editor support.
Pursuit is one of the coolest things. It hosts the API documentation and lets us search it by package, module, function names, and type signatures.
There is also purs-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 and Recommended Tooling for PureScript series.
JavaScript-backend specific
If you import libraries from JavaScript, you need a package manager. You can use npm (commonly used), yarn, or whatever.
You also need a bundler to deal with JavaScript imports, smoosh your files, etc. You can get started with esbuild. The most popular alternatives areĀ webpack andĀ parcel, 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.
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:
// JavaScript file
"use strict";
export const square = function (n) {
return n * n;
};
-- PureScript file
module Test where
foreign import square :: Number -> Number
-- 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):
// JavaScript side
export { default as reactPlayerImpl } from 'react-player';
-- PureScript side
foreign import reactPlayerImpl
:: ReactComponent { url :: String, light :: Maybe Boolean }
-- 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 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:
-- PureScript file
module Test where
first :: Int -> Int -> Int
first a _ = a
// JavaScript file
import { gcd } from 'Test';
first(10)(2);
š”Ā You can read more about interoperability in the book, docs, reference, or anywhere else.
Frameworks
At the moment, the most popular UI Frameworks in PureScript ecosystem are Halogen and React.
š”Ā Checkout Real World Halogen and Real World PureScript React, 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:
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Ā family of PureScript packages, which include basic components, specific components, starter applications, Hooks API, 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 or Getting Started Guide.
- Start learning with free PureScript By Example Book.
- Start talking on PureScript DiscordĀ server.
- Start playing with PureScript at try.purescript.org
Last winter, together with a two sets of my ex-colleagues, we shared our experiences of using PureScript in production.
And last but not least, go build some stuff.
References and links
- PureScript By Example
- PureScript DiscourseĀ instance
- Functional Programming Made Easier
- PureScript: Cookbook
- Thomas Honeyman Articles
- PureScript: Jordanās Reference
- Markās alethic.art
- Pursuit
Top comments (0)