Skip to content
This repository has been archived by the owner before Nov 9, 2022. It is now read-only.


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
This branch is 110 commits ahead, 354 commits behind purescript:master.

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

Standalone Backend

Deprecated - see the standalone purerl backend at purerl/purerl

PureScript - Erlang backend

A small strongly typed programming language with expressive types, written in and inspired by Haskell.

The original PureScript project compiles to JavaScript, but this fork is a backend targetting Erlang source. The purerl organisation hosts ports of some core libraries.

To use it, it is recommended to use psc-package and the purerl package sets. In a psc-package project, compile with something like

psc-package sources | xargs purs 'src/**/*.purs'

or if using bower:

purs 'bower_components/purescript-*/src/**/*.purs' 'src/**/*.purs'

Then build and run the Erlang output:

erlc -o ebin/ output/*/*.erl
erl -pa ebin -noshell -eval '(main@ps:main())()' -eval 'init:stop()'

See hello-world example.

Erlang/OTP 19 supported, subtle & catastrophic bugs have been observed with earlier versions. If you do try with an earlier version minimum 17 is suggested due to character encoding.


Module names Foo.Bar are transformed to a lower-snake cased form foo_bar (any non-initial uppercase chars will be preserved as such), with a suffix @ps to avoid clashing with built-in erlang modules.

Top level declarations are uniformly output as nullary functions. Identifiers are preserved, with quoting if required. Thus a normal invocation of the output will look like (main@ps:main())().


PureScript type Erlang type Notes
Int integer() Arbitrary precision - no longer a Bounded
Number float()
Boolean boolean()
String binary() (utf8 encoded)
Array array() Not to be confused with erlang [] list syntax.
Records #{atom() => any()} Map keyed by atoms
Tagged union Tuple with tag element e.g. Some 42 is {some, 42}
Newtype as underlying type
Functions Function (arity 1 - but see FFI)
Data.Function.Uncurried.FnX Function (arity X) Actual higher arity functions - for 'uncurried' functions from tuples see Erl.Data.Tuple
Erl.Data.List list() Native lists via purescript-erl-lists
Erl.Data.Tuple tuple() Native tuples via purescript-erl-tuples
Erl.Data.Map tuple() Map with homogenous key/value types


In place of .js FFI files, the Erlang backend has .erl FFI files. As per the regular compiler since 0.9, these must be placed along the corresponding .purs file with the same name.

Module name: Foo.MyModule PureScript file Foo/MyModule.purs Erlang file: Foo/MyModule.erl Erlang module: foo_myModule@foreign

Note that the FFI code for a module must not only be in a file named correctly, but the module must be named the same as the output module with @foreign appended (so not following the Erlang module naming requirement until this gets copied to output).

FFI files MUST export explicitly the exact set of identifiers which will be imported by the corresponding PureScript file. The compiler will check these exports and use them to inform codegen.

Auto-currying: functions can be defined with any arity. According to the arity of the export (parsed from the export list) the compiler will automatically apply to the right number of arguments. By extension, values are exported as a function of arity 0 returning that value.

An example:

module Foo.Bar where

foreign import f :: Int -> Int -> Int -> Int

f(X, Y, Z) -> X + Y * Z.

This could also have been defined as


f(X) ->
  fun (Y) ->
    fun (Z) ->
      X + Y * Z


A small strongly typed language that compiles to Erlang (not JavaScript)







No packages published


  • Haskell 87.0%
  • PureScript 9.4%
  • CSS 1.6%
  • Yacc 1.5%
  • Shell 0.2%
  • JavaScript 0.2%
  • Other 0.1%