Skip to content

WojciechP/funds

 
 

Repository files navigation

Functional Utilities and Data Structures

Travis branch npm

This package provides a collection of tools for functional programming. They are all strongly typed for easy consumption from TypeScript.

The package contains a set of ES6 modules, so you will most likely need a preprocessor and polyfills if you intend to use it in a browser.

npm install --save funds will get you started.

Package contents

funds/core

The main reason for this module are functions with extra helpers for composition and currying:

// in funds/core:

interface Fun<A, B> {
  (a: A): B
  andThen<C>(f: (b: B) => C) => Fun<A, C>
}

export function mkFun<A, B>(f: (a: A) => B): Fun<A, B>


export interface Fun2<A1, A2, B> extends Fun<A1, Fun<A2, B>> {
  (a1: A1, a2: A2): B
  (a1: A1): Fun<A2, B>
  andThen<C>(f: (partial: (a2: A2) => B) => C): Fun<A1, C>
}

export function mkFun2<A1, A2, B>(f: (a1: A1, a2: A2) => B): Fun<A1, A2, B>

A Fun<A, B> is just a function that takes A and produces B, but which can be easily composed using andThen method:

// your code:

var f = mkFun(n => n+2)
var g = mkFun(n => 2*n)

var composed = f.andThen(g)

console.log(composed(6))  // prints (6+2)*2 = 16

A Fun2<A1, A2, B> is a two-argument function which can be composed or curried:

// your code:

var f = mkFun2((a, b) => a + 2*b)
var addFour = f(4)  // this is now a partially applied function, with a=4 and waiting for b

console.log(addFour(1))  // prints 4 + 2*1 = 6
console.log(addFour.andThen(t => t*3)(7))  // prints (4 + 2*x)*3 for x = 7, which is 54

// let consider a wrapper that wraps numeric functions:
var wrap = function(f) {
  return function wrapped(n) {
    console.log(`Got argument ${n}`)
    var result = f(b)
    console.log(`Returning ${result}`)
    return result
  }
}

const addFourWithLogging = f.andThen(wrap)(4)
console.log(addFourWithLogging(5))
// > 'Got argument 5'
// > 'Returning 14'
// > '14'

funds/data: Universal Immutable Data Types

Maybe

import { Maybe, just, nothing } from 'funds/data'

var j5 = just(5)
console.log(j5.isJust) // true

var j6 = j5.map(t => t+1)
console.log(j6.run) // 6

var j7 = j6.flatMap(t => just(t+1))
console.log(j7)  // Just(7)
console.log(j6.flatMap(t => nothing())) // Nothing

console.log(nothing().isJust)  // false
console.log(nothing().run)  // null

Either

import { Either, left, right } from 'funds/data'

var r5 = right(5)

var r6 = r5.map(t => t+1)
var r7 = r5.flatMap(t => right(t+1))
var le = r7.flatMap(t => left(-t))
var result = le.cata(
  function ifLeft(leftVal) { return `Negative: ${leftVal}` },
  function ifRight(rightVal) { return `Positive: ${rightVal}` }
)
console.log(result)  // 'Negative: -7'

funds/optics: Getters, Setters, Lenses, and Prisms

Optics are various flavors of functional references to a part of bigger data structure. They crucial kind is a lens:

import { mkLens } from 'funds/optics'

const john = { 
  name: 'John',
  email: 'john@example.com'
}

const email = mkLens(
  function get(person) { return person.email },
  function set(email, person) { return { name: person.name, email: email }}
)

console.log(email.get(john))
// > 'john@example.com'
console.log(email.modify(oldEmail => oldEmail.replace('.com', '.org')))
// > { name: 'John', email: 'john@example.org' }

All optics are functional tools, meaning they do not mutate data. The functions set and modify return updated copies of original data instead.

About

Functional Utilities and Data Structures for TypeScript and JavaScript

Resources

Stars

Watchers

Forks

Packages

No packages published