Function Pattern Matching

Functional Pattern Matching for a function.

Basically an idea that we can declare a function multiple times passing arguments (or matching argument) as parameters, and getting different statements depending on that parameter.

In General this might just look like a syntax sugar for an if statement or a switch case, but that could be much more.

I'd think this would be a great functional addition to the functional arrow functions, partial-applications, do blocks, or pipeline-operators.

Lets look at the most basic example a fibonacci sequence:

image

Let look at the ways we can define it, starting from the most reasonable lines of code to least code possible.

Switch case, an overkill imo.

function fibonacci(n) {
  switch(n) {
    case 0:
    case 1:
      return 1
    default:
      return (fibonacci(n-1) + fibonacci(n-2))
  }
}

Here we cant check for negative value and write something like case n >= 2

Lets look at most basic way to do this correctly

function fibonacci(n) {
  if(n == 0 || n == 1) {
    return 1
  } else {
    return (fibonacci(n-1) + fibonacci(n-2))
  }
}

I think we can improve on this function though, lets make it functional and readable

const fibonacci= (n) => {
  if(n == 0 || n == 1)
    return 1
  else
    return (fibonacci(n-1) + fibonacci(n-2))
}

I personally think this looks nice, functional and readable.

Lets try to create such a function with minimal code possible

let fib = n => n <= 1 ? 1 : fib(n-1) + fib(n-2)

Do you think thats readable?
Well I might write some ninja code here and there and not care if a other developers can read it, but imagine you see => n <=, my initial reaction would be Hey that's a smiley face


Proposal

Ability to define a function with arguments rather than parameters

So let me show you how i think this function should look and maybe some variations.
example 1 with const

const fib = 0 => 1
const fib = 1 => 1
const fib = n => fib(n-1) + fib(n-2)

Yes, this will throw an exeption atm, but maybe we can have a special word like async?
example 1 with pat

pat fib = 0 => 1
pat fib = 1 => 1
pat fib = n => fib(n-1) + fib(n-2)

pat being shorthand for pattern

Both exmaples 1 and 2 would yeild something like

const fib(n) {
  if(n === 0) { return 1 }
  if(n === 1) { return 1 }
  return fib(n-1) + fib(n-2)
}

Where the last line return woud be the actual statement that wasn't matched, and everything that did goes on top.


Or some other type of syntax feature like new TC39 proposal pipes?

const fib = n =>
  |> 0 = 1
  |> 1 = 1
  |> n = fib(n-1) + fib(n-2)

This still does not fix a problem with negative numbers....
We can improve on this feature with some matching for example:

const fib = n =>
  |> n <= 1 = 1
  |> n >= 2 = fib(n-1) + fib(n-2)

I think this is quite readable and really functional. And just imagine what can we do if this could be combined with pipeline-operator and partial-application proposals...

Further reading and insporation
Haskell Patterns Tutorial
Haskell Pattern matching stackoverflow
Syntax in function (learn you haskell)

What Do you think? Is this is readable? How can this be impoved? Are there similar features like that in F# or Elixir?

1 Like

Are you familiar with the existing stage 1 Pattern Matching proposal for JS? GitHub - tc39/proposal-pattern-matching: Pattern matching syntax for ECMAScript

3 Likes

Yes, this is somewhat different syntax approach for a same result.

Basically I've copied the idea from Haskell. It's a more functional approach.

Basically when you pass args as params function handles differently.

const sum = (a,b) => a + b

const sum = (5,6) => "lol, this is not what you expected"

The main idea is that Ive tried to make this approach more intuitive.

Yea, looking at this further, the match syntas solves the switch case problem, here i wanted to loose unnesessary syntax tohugh, with some sort of do block, mattern match syntax. This syntax is however is for functions specifically