psc-package and optimisation
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 theOrd
instance forInt
:(((data_ord:greaterThan())((data_ord:ordInt())))(N))(1000)
becomesN > 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.