Skip to content

Instantly share code, notes, and snippets.

@SimonMeskens
Last active August 4, 2017 11:30
Show Gist options
  • Save SimonMeskens/eb86676a0546023e33cf753def594073 to your computer and use it in GitHub Desktop.
Save SimonMeskens/eb86676a0546023e33cf753def594073 to your computer and use it in GitHub Desktop.
Typed Static-land

General

  • Refactor all isEqual functions to equals
  • Add namespaced fantasy methods
  • Write tests for the laws in Static-land

List

  • Look at unifying List with other structures #31
  • Add fold primitive to internals
  • Add List/of
  • Add List/zero
  • Add List/alt
  • Add List/map #51
  • Add List/filter
  • Add List/ap
  • Add List/reduce
  • Add List/chain
  • Add List/traverse
  • Add List/extend

Proposal: Typed Static-land compliance

This document outlines a strategy that promises at the very least a guarantee a library will not become incompatible with the Static-land specification and at best allows a path towards full compatibility, without clobbering users with hard to understand terminology, such as monoids, monads and functors.

Rules

A list of Static-land reserved function names, with TypeScript types, is provided at the bottom

  1. No type will export a function name out of the reserved list, without also sharing type and behavior
  2. If a function shares the type of a Static-land reserved function and has the same behavior, either an alias is made or the method receives the same name

The first rule simply means that if you have, for example, a map method that's not compliant with the Functor.map, you name it transform or select instead. Array.map is compliant with Functor.map, it's actually unusual for name collisions to happen, as Static-land is based on vanilla JavaScript. The second rule is just to make sure that if there exists, for example, a flatMap compliant with Chain.chain (as in many libraries), compatibility with Static-land is ensured by either having an alias or simply naming it chain in the first place.

Fantasy-land compliance

Each type that exports Static-land compliant functions also has non-enumerable namespaced methods on the type. For example, if a map function exists, the type itself also has a fantasy-land/map property, which is compliant with Fantasy-land (usually the same signature as Static-land, but with this functioning as the type to act on. By making these non-enumerable, you only come across them if you're looking (no pollution of the type). These act as a formal protocol for libraries such as Ramda, so they know how to handle that type.

Static-land reserved functions

For expected behavior, check the Static-land spec. These mostly do exactly what you expect them to do. Static-land never collapses though, so a list of lists is never automatically flattened, for example. Obviously, names of parameters are not important, signature is.

In these, Type is a stand-in for the type in question, generic parameters are noted as A, B, C, etc. A type can always have more generic parameters than specified, but never less.

  equals(a: Type, b: Type): boolean
  lte(a: Type, b: Type): boolean
  concat(a: Type, b: Type): Type
  empty(): Type
  map<A, B>(f: (a: A) => B, ta: Type<A>): Type<B>
  bimap<A, B, C, D>(fa: (a: A) => B, fc: (c: C) => D, ta: Type<A, C>): Type<B, D>
  contramap<A, B>(f: (a: A) => B, tb: Type<B>): Type<A>
  promap<A, B, C, D>(fa: (a: A) => B, fc: (c: C) => D, tbc: Type<B, C>): Type<A, D>
  ap<A, B>(f: Type<(a: A) => B>, ta: Type<A>): Type<B>
  of<A>(a: A): Type<A>
  alt<A>(a: Type<A>, b: Type<A>): Type<A>
  zero<A>(): Type<A>
  chain<A, B>(f: (a: A) => Type<B>, ta: Type<A>): Type<B>
  chainRec // Not easily typable in TypeScript
  reduce<A, B>(f: (a: A, b: B) => A, a: A, tb: Type<B>): A
  extend<A, B>(f: (ta: Type<A>) => B, ta: Type<A>): Type<B>
  extract<A>(ta: Type<A>): A
  traverse // Not easily typable in TypeScript
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment