Package set

With PureScript 0.10.2 the psc-package package manager has been kicked off. In contrast of the pain of resolving bower dependencies for forked packages for the Erlang backend, there is now a package set available which should contain packages which have been ported (in their FFI), which work without any changes (no FFI), and those which are Erlang-specific. To use this you just need to add the purerl package set in psc-package.json, e.g. from hello-world:

{
    "name": "hello-world",
    "set": "erl-0.10.1",
    "source": "https://raw.githubusercontent.com/purerl/package-sets/erl-0.10.1/packages.json",
    "depends": [
        "console",
        "prelude"
    ]
}

Just now building is a slightly awkward without support in something like pulp; I’m using the following command to build:

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

Optimisation

In an earlier post I lamented that while Erlang guards are used in the output, they are not used in any real sense. The input

isLarge :: Maybe Int -> Boolean
isLarge = case _ of
  Just n | n > 1000 -> true
  _ -> false

results in

isLarge() ->
  fun (V) -> begin
    _@2 = (fun
      ({ just, N }) -> ((((data_ord:greaterThan())((data_ord:ordInt())))(N))(1000));
      (_) -> false
    end(V)),
    (fun
      ({ just, N }) when _@2 -> true;
      (_) -> false
    end(V))
  end
end.

Having added some optimisations, this now becomes (with a little whitespace tweak):

isLarge() -> fun
  ({ just, N }) when N > 1000 -> true;
  (_) -> false
end.

This comes due to a few optimisations, mostly lifted from the existing JS backend:

  • Inlining of common operations, such as greaterThan in the Ord instance for Int: (((data_ord:greaterThan())((data_ord:ordInt())))(N))(1000) becomes N > 1000
  • Removal of extraneous begin/end blocks
  • Inlining of certain guard expressions

For inlining guard expressions, if the clause bodies are sufficiently simple as to be permissable as Erlang guard expressions (broadly speaking arthmetic and boolean expressions, variables but no function applciations), then the expression is hoisted up to a guard. Any more complex guards are left as-is.

The “magic do” optimisation for the Eff monad is now also implemented (sans whileE, untilE which don’t fit so well), leaving this

main = do
  x <- pure $ 1 + 2
  log $ show x
  pure unit

to output this:

main() -> fun
  __do() ->
  X = 1 + 2,
  (((control_monad_eff_console:log())((((data_show:show())((data_show:showInt())))(X))))()),
  (data_unit:unit())
end.