PureScript Documentation

repository·master·Indexed 21 days ago

https://github.com/purescript/documentation

Central hub for PureScript, a strongly typed language that compiles to JavaScript. Includes language references, guides on the Foreign Function Interface (FFI) and common operators, and ecosystem information regarding the Spago build tool, PSCi REPL, and various editor supports for VSCode, Vim, IntelliJ, Emacs, and Sublime Text. Also provides details on alternative backends for C++, Erlang, C, Nix, and Lua, as well as troubleshooting for compiler errors like ArgListLengthsDiffer.

Tokens
66.2K
Snippets
233
Records
357
Agent score
76%

What's inside PureScript

  1. Explore alternative PureScript backends

    master

    While psc defaults to a JavaScript backend, several alternative backends exist for targeting different runtimes. These are categorized by their maintenance status. Use the 'Actively Maintained' list for current development needs.

    Actively Maintained Backends

    TargetSource CodePureScript VersionUsability
    C++11 or Gopurescript-native0.14.xPasses all applicable tests in purescript/tests/purs/passing
    Erlangpurerl0.15.14
    C (Clang)purec
    Nixpurenix0.14.4
    Luapurescript-lua0.15.9Alpha

    Stale Backends

    Note that the following projects are considered stale and may not support recent PureScript versions or be suitable for production use:

    TargetSource CodePureScript Version
    Lualua-purescript/purescript0.9.1.0
    Truffle (Graal)truffled-purescript0.7.5.x
    Luapsc-lua0.5.x
    PythonPurescript-to-Python
    PythonPyreScript0.9.1
    Haskell (GHC)thran0.11.6
    Clojure (JVM)purescript-clojure
    Kotlinpskt
    Python >= 3.5purescript-python0.13.x
    Datalogpsc-query0.11.7
    Swiftpureswift
  2. Use case expressions for pattern matching

    master

    The case and of keywords allow deconstructing values based on their constructors.

    • Multiple values: You can match on multiple values simultaneously by separating them with commas in the head and the cases.
    • Guards: case expressions support guards using the | symbol.
    • Anonymous arguments: Use a single underscore _ to match a value without binding it to a name.
    f :: Maybe Boolean -> Either Boolean Boolean -> String
    f a b = case a, b of
      Just true, Right true -> "Both true"
      Just true, Left _ -> "Just is true"
      Nothing, Right true -> "Right is true"
      _, _ -> "Both are false"
    
    -- Using guards
    f x = case x of
      Left x | x == 0 -> "Left zero"
             | x < 0 -> "Left negative"
             | otherwise -> "Left positive"
      Right _ -> "Right"
    
    -- Anonymous argument
    case _ of
      0 -> "None"
      1 -> "One"
      _ -> "Some"
  3. Understand Rows

    master

    A row is an unordered collection of named types. Rows have the kind Row k and cannot exist as values; they are used in type signatures to define records or other structures.

    • Closed Rows: Defined by separating fields with commas and using :: between labels and types. Example: ( name :: String, age :: Number )
    • Open Rows: Defined by separating specified fields from a row variable using a pipe |. Example: ( name :: String, age :: Number | r )
  4. Define and use binary operators

    master

    In PureScript, operators are regular binary functions (type a -> b -> c). You can create operator aliases using infixl, infixr, or infix followed by a precedence integer (0-9).

    • infixl: Left-associative. Repeated applications are bracketed from the left.
    • infixr: Right-associative. Repeated applications are bracketed from the right.
    • infix: Non-associative. Repeated use of the same operator in a single expression is disallowed and results in a NonAssociativeError.

    Types can also be aliased as operators using the type keyword.

    data List a = Nil | Cons a (List a)
    
    append :: forall a. List a -> List a -> List a
    append xs Nil = xs
    append Nil ys = ys
    append (Cons x xs) ys = Cons x (append xs ys)
    
    -- Define 'append' as a right-associative operator '<>' with precedence 5
    infixr 5 append as <>
    
    -- Usage
    oneToSix = (Cons 1 (Cons 2 Nil)) <> (Cons 3 Nil)
  5. Use the Warn type class for custom compiler warnings

    master

    The Warn type class (available in the Prim module) allows you to trigger custom compiler warnings by adding a constraint to a function. Warn is indexed by a Symbol. When the compiler solves a Warn constraint, it will print the provided message as a user-defined warning during compilation.

    This is useful for providing guidance to users, such as suggesting alternative functions during a deprecation process.

    import Data.Text (Text)
    import Prim (Warn)
    
    -- Example of a function that triggers a warning when used
    notBad :: Warn (Text "`notBad` is deprecated. Prefer `better` instead.") => Int
    notBad = 21
    
    better :: Int
    better = 42
  6. Understand Polymorphic Types

    master

    Expressions can be polymorphic using the forall quantifier. This allows a function to operate on any type provided.

    Example with type inference:

    identity x = x
    -- Inferred as: forall t0. t0 -> t0

    Example with explicit type annotation:

    identity :: forall a. a -> a
    identity x = x
  7. Use compiler-solvable type classes

    master

    Certain type classes are automatically solved by the PureScript compiler. You do not need to provide explicit instances or use derive instance statements for these classes. They are primarily used for type-level operations, error reporting, and row manipulations. These classes are located in the Prim modules.

    foo :: forall t. (Warn "Custom warning message") => t -> t
    foo x = x
  8. Understanding when `Coercible` unwrapping occurs

    master

    The PureScript compiler only unwraps finite chains of newtypes.

    If a newtype declaration contains an intervening constructor (like a function arrow ->), the compiler will attempt to unwrap the newtype to reach that constructor. If that unwrapping leads back to the same newtype, it results in the PossiblyInfiniteCoercibleInstance error.

    However, if the newtype is strictly recursive without an intervening constructor, the compiler avoids the loop. For example:

    newtype N a = N (N a)
    type role N representational

    When solving for Coercible (N a) (N b) in this specific case, the compiler does not unwrap the N constructor; instead, it decomposes the requirement to Coercible a b, which can then be discharged by the context.