41
@FGRibreau Implementing pattern-matching in JavaScript

Implementing pattern-matching in JavaScript (short version)

Embed Size (px)

Citation preview

@FGRibreau

Implementing pattern-matching in JavaScript

@FGRibreau

Implementing pattern-matching in JavaScript…or how to play with EcmaScript shortcoming

0 context

@FGRibreau

Une syntaxe de pattern-matching en JS ? Sortez l'artillerie lourde.

@FGRibreau

_.flatten(links).map(link => { [{protocol: 'HTTP'}]: => 1, [{protocol: 'AMQP'}]: => 2 });

It would it be awesome to use some pattern-matching there right?

@FGRibreau

SyntaxError: /Users/FG/www/iadvize-services-orchestration-tools/src/api/src/repositoryManagers/github.js: Unexpected token (185:32) 183 | 184 | _.flatten(links).forEach(link => { > 185 | [{protocol: 'HTTP'}]: => 1, | ^ 186 | [{protocol: 'AMQP'}]: => 2 187 | }); 188 |

... and of course it’s not JS valid syntax

1 goal

@FGRibreau

syntactically short javascript-minded syntax functionally-way

I wanted a pattern-matching library

2 syntax

@FGRibreau

links.map(link => { [{protocol: 'HTTP'}]: => 1, [{protocol: 'AMQP'}]: => 2 });

Ok, so this is not valid, what precisely is not valid and

how can we make it valid?

@FGRibreau

links.map(link => { [{protocol: 'HTTP'}]: () => 1, [{protocol: ‘AMQP'}]: () => 2 });

links.map(link => { [{protocol: 'HTTP'}]: 1, [{protocol: ‘AMQP'}]: 2 });

links.map(link => { [{protocol: 'HTTP'}]: => 1, [{protocol: 'AMQP'}]: => 2 });

@FGRibreau

{ [{protocol: ‘HTTP'}]: 1, [{protocol: ‘AMQP’}]: 2 }

The rest is syntactically valid

ES6 "computed property names"

{ [{protocol: ‘HTTP’}]: () => 1, [{protocol: ‘AMQP’}]: () => 2 }

@FGRibreau

links.map(link => {}) [undefined, undefined]

links.map(link => {1}) [undefined, undefined]

links.map(link => {return 1}) [1,1]

links.map(link => 1) [1,1]

Syntactically valid, semantically invalid … but then I won't have my pattern matching.

@FGRibreau

BUT…

@FGRibreau

If I go from there…_.flatten(links).map(link => { [{protocol: 'HTTP'}]: => 1, [{protocol: 'AMQP'}]: => 2 });

@FGRibreau

If I go from there…_.flatten(links).map(link => { [{protocol: 'HTTP'}]: => 1, [{protocol: 'AMQP'}]: => 2 });

_.flatten(links).map(match({ [{protocol: 'HTTP'}]: 1, [{protocol: 'AMQP'}]: 2 }));

…to there…

@FGRibreau

… then it’s syntactically correct!

_.flatten(links).map(match({ [{protocol: 'HTTP'}]: 1, [{protocol: 'AMQP'}]: 2 }));

@FGRibreau

… then it’s syntactically correct!

_.flatten(links).map(match({ [{protocol: 'HTTP'}]: 1, [{protocol: 'AMQP'}]: 2 }));

@FGRibreau

… would be great too !

const linkNumber = match(link,{ [{protocol: 'HTTP'}]: 1, [{protocol: 'AMQP'}]: 2 });

3 Semantic

@FGRibreau

{ '[object Object]': 2 }

evaluates to

ES6 "computed property names"

{ [{protocol: 'HTTP'}]: 1, [{protocol: 'AMQP'}]: 2 }

plz fix this

plz fix this

@FGRibreau

evaluates to

ES6 "computed property names"

{ [when({protocol: ‘HTTP’})]: 1, [when({protocol: ‘AMQP'})]: 2 }

{ '{"protocol":"HTTP"}': 1, '{"protocol":"AMQP"}': 2 }

@FGRibreau

evaluates to

ES6 "computed property names"

{ [when({protocol: ‘HTTP’})]: 1, [when({protocol: ‘AMQP'})]: 2 }

{ '{"protocol":"HTTP"}': 1, '{"protocol":"AMQP"}': 2 }

@FGRibreau

Order is lost by match’s object

.map(match({ [when.range(0, 43)]: 42, [when(42)]: 72 }))

when.range(0,43) => '["Symbol(match.pattern.RANGE)",0,43]' when(42) => '[42]'

JS objects are an unordered collection of properties

@FGRibreau

Fixing properties declaration

?

.map(match({ [when.range(0, 43)]: 42, [when(42)]: 72 }))

.map(match(new Map([ [ when.range(0, 43), 42 ], [ when(42), 72 ], [ when(), 'never should be hit' ] ])))

NO!

@FGRibreau

Fixing properties declaration

?

.map(match({ [when.range(0, 43)]: 42, [when(42)]: 72 }))

.map(match([ [ when.range(0, 43), 42 ], [ when(42), 72 ], [ when(), 'never should be hit' ] ]))

NO!

plz fix this

plz fix this

@FGRibreau

Fixing properties declaration

.map(match({ [when.range(0, 43)]: 42, [when(42)]: 72 }))

- same callsite - single thread - sequential evaluation

@FGRibreau

Fixing properties declaration

.map(match({ [when.range(0, 43)]: 42, [when(42)]: 72 }))

- same callsite - single thread - sequential evaluation

@FGRibreau

Fixing properties declaration

when.range(0,43) => '[0, "Symbol(match.pattern.RANGE)",0,43]' when(42) => '[1, 42]'

… #problemSolved …

.map(match({ [when.range(0, 43)]: 42, [when(42)]: 72 }))

- same callsite - single thread - sequential evaluation

@FGRibreau

How to get matched value?

const fact = match({ [when(0)]: 1, [when()]: n * fact(n-1) });

fact(10);

n is not defined

@FGRibreau

How to get matched value?

const fact = match({ [when(0)]: 1, [when()]: n * fact(n-1) });

fact(10);

simple, use a function:

const fact = match({ [when(0)]: 1, [when()]: (n) => n * fact(n-1)});

fact(10); // 3628800

@FGRibreau

How to get matched value?

const fact = match({ [when(0)]: 1, [when()]: n * fact(n-1) });

fact(10);

simple, use a function:

const fact = match({ [when(0)]: 1, [when()]: (n) => n * fact(n-1)});

fact(10); // 3628800

4 wrap up

@FGRibreau

François-Guillaume

RIBREAU@FGRibreau

Tightly crafted developer oriented online real-time monitoring and administration service for Redis.

Join us

Frontend Dev - Backend Dev Fullstack Dev - DevOps

#scala #nodejs #react #docker #xmpp