Skip to content

ephetic/functional

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

37 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

functional

Installation

yarn add @ephetic/functional

Erlang-inspired pattern matching

Patterns are checked in order, stopping with the first match. If no patterns match, the generated function will return undefined.

The pattern wildcard is the function itself (and can be aliased to any symbol you prefer).

Examples

import { matcher as m } from 'functional'

Match on constants or predicate functions

const isHi = m(['hi', true])

console.log(isHi('hi'))     // true
console.log(isHi('hello'))  // undefined

const fact = m(
  [1, 1],
  [m, n => n * fact(n-1)]
)

const fibo = m(
  [n => n <= 2, 1],
  [m, n => fibo(n-1)   fibo(n-2)]
)

Type/contract checking example

const t = (types, fn) => 
  process.env.NODE_ENV == 'production' 
  ? fn 
  : m([types, fn], 
      [m, (...args) => {throw `Type Check error: [${args}] doesn't match [${types}].`}])

const Integer = n => n === (n|0)
const addi = t([Integer, Integer], (a,b) => a   b)

const NonnegativeInteger = n => Integer(n) && n >= 0
const powish = t([Number, NonnegativeInteger], (b, e) => e > 0 ? b * pow(b, e - 1) : 1)
console.log(powish(2.2,3)) // works
console.log(powish(2,-3))  // throws

Match with RegExp

const isLikeHi = m([/.*hi.*/, s => `${s} is close enough`])

Match on argument contracts, values, and don't-cares

const secondIsNumber = m(
  [ [m, Number], (a,b) => console.log(`${b} is a Number`)],
  [ m,           (a,b) => console.log(`${b} is not a Number`)]
)

secondIsNumber('asdf', 2)   // 2 is a Number
secondIsNumber(2, 'asdf')   // asdf is not a Number

Note:

  • Number here is the Number constructor which returns falsy NaN for anything that doesn't parse as a number. Contructor type-checking does not currently work (it can cause false positives when called internally as a predicate).
  • To test a single array, wrap them in an array to indicate an argument or use an object literal with index keys; e.g. [[m, m]] or {0: m, 1: m, length: 2} (include length for exact match).

Match on given object shape

const isDuckman = m([{name: 'Duckman', age:40}, () => console.log('Duuuuckmaaaaan!')])
isDuckman({name: 'Duckman', age:40})  // Duuuuckmaaaaan!
isDuckman({name: 'Duckman'})          // undefined

const isDuckPerson = m([{name: m, age: m}, () => console.log('wubba lubba dub dub')])
isDuckPerson({name: 'Rick', age: 55}) // wubba lubba dub dub

Partial function application

Uses itself as wildcard to leave arbitrary parameters unbound.

import { partial as p } from 'functional'
const add = (a,b) => a   b
const div = (a,b) => a / b

const add1 = p(add, 1)
const halve = p(div, p, 2)

About

ES6 Functional Helpers

Resources

Stars

Watchers

Forks

Packages

No packages published