I just uploaded a patch to the PureScript compiler here which changes the way constructor types are representated in the generated JS code.
Right now, the following code:
data Tuple a b = Tuple a b
data Either a b = Left a | Right b
compiles to:
var Tuple = (function () {
function Tuple(value0, value1) {
this.value0 = value0;
this.value1 = value1;
};
Tuple.create = function (value0) {
return function (value1) {
return new Tuple(value0, value1);
};
};
return Tuple;
})();
var Left = (function () {
function Left(value0) {
this.value0 = value0;
};
Left.create = function (value0) {
return new Left(value0);
};
return Left;
})();
var Right = (function () {
function Right(value0) {
this.value0 = value0;
};
Right.create = function (value0) {
return new Right(value0);
};
return Right;
})();
With my patch, it compiles to:
var Tuple = function (value0, value1) {
return [ "Tuple", value0, value1 ];
};
var Left = function (value0) {
return [ "Left", value0 ];
};
var Right = function (value0) {
return [ "Right", value0 ];
};
(Q: What happened to the .create
version? A: I currently generate an anonymous function every time a constructor is partially applied. This is not very common in the code I’ve analyzed.)
(Q: Why is the first element a string and not an integer or unique object? A: I’m working on it. It should reduce the code size mentioned below even more!)
Benchmark 1
I ran the patched compiler on purescript-halogen-realworld and the minified size of the bundle went from 652.59KB to 609.06KB.
Benchmark 2
I picked a package which uses sum types extensively: purescript-unordered-collections and wrote a simple program to construct a huge map 20 times:
module Main where
import Prelude
import Data.Array ((..))
import Data.Foldable (foldl)
import Data.Map as Map
import Effect (Effect)
import Effect.Console (log)
main :: Effect Unit
main = go 20
where
array = 1 .. 100000
go 0 = pure unit
go n = do
let map = foldl (\acc x -> Map.insert x x acc) Map.empty array
log $ show $ Map.size map
go (n - 1)
The runtime of this function went from ~4.1 seconds to ~3.2 seconds with Node v11.6.0.
Trying it out
- Check out my fork of the compiler: https://github.com/utkarshkukreti/purescript/tree/compact-constructor-repr-at-runtime and build it with
make build
. - Run
stack exec bash
. This will drop you into a bash instance wherepurs
will point to the fork. Verify this withwhich purs
. (Thanks to @LiamGoodacre on Slack for this tip!) -
cd
into your project and compile it normally (e.g. withpulp build
).
All the compiler tests pass with my patch. I compiled purescript-halogen-realworld and tried it out and it seems to be working fine. There might still be bugs in either my patch or some FFI code that relies on the current object based representation of data constructors.
Please let me know what you all think! Is a change like this desirable as long as it causes no regressions?