Pattern matching in JS on a PureScript sum-of-products type

Viewed 31

I have an algebraic sum-of-products type in PureScript:

data IO
    = Menu (Word8 -> Effect IO)
    | LongMessage (Array String) (Effect IO)
    | ShortMessage String (Effect IO)
    | End 

initialize :: Effect IO

I'd like to call initialize from JavaScript, and then consume its result. If I run Main.initialize() from JavaScript, I get a JS Object that prints like the following to console:

LongMessage3 {value0: Array(15), value1: ƒ}
value0: (1) ['foo']
value1: ƒ __do()
[[Prototype]]: Object

What would the JavaScript code look like that recognizes this object as a value corresponding to the LongMessage constructor?

1 Answers

First, to answer questions like this, you can just look at the compiled JS code yourself. It's located in ./output/My.Module.Name/index.js. Just open it and take a look.

But for completeness, here's the answer:

The current version of PureScript (0.15.2 as of this writing) compiles ADTs to a set of JS objects with unique prototypes.

I'm going to use a smaller example, because yours is a bit too large to be legible. Let's say my ADT looks like this:

data X = Y Int | Z String Boolean

a = Y 42
b = Z "foo" false

This would yield roughly the following JS (I say "roughly" because it's a bit more elaborate, but the essence is the same):

function Y(value0) {
  this.value0 = value0
}

function Z(value0, value1) {
  this.value0 = value0
  this.value1 = value1
}

var a = new Y(42)
var b = new Z("foo", false)

When constructed like this, values of the type can be tested for the particular constructor by checking the prototype via instanceof. So, for example, the following:

c = case a of
  Y _ -> "It's a Y"
  Z s _ -> "It's a Z with " <> s

would translate roughly to:

var c = (() => {
  if (a instanceof Y) {
    return "It's a Y"
  }

  if (a instanceof Z) {
    return "It's a Z with " + a.value0
  }

  throw new Error("Invalid pattern match")
})()

A footnote: in your example the constructor seems to be named LogMessage3 instead of LogMessage. This tells me that you're probably executing a bundle. During bundling functions may get renamed to avoid naming conflicts - that's where the "3" comes from.

Related