Skip to content

Instantly share code, notes, and snippets.

@fvilante
Created April 18, 2019 21:58
Show Gist options
  • Save fvilante/2639be00035a938d50a7d27915b7ed59 to your computer and use it in GitHub Desktop.
Save fvilante/2639be00035a938d50a7d27915b7ed59 to your computer and use it in GitHub Desktop.
An example of Functor in TypeScript. You can run this on https://www.typescriptlang.org/play/
// ==============================================
// PROPOSAL OF SOLUTION
// ==============================================
// ================================
// Emulate nominal type-system
// ================================
type Kind<K> = { kind: K }
type Value<T> = { value: T }
type Container<K, T> = Kind<K> & Value<T>
type Unit<K> = <T>(value: T) => Container<K, T>
const Unit =
<K extends string>(kind: K):Unit<K> => <T>(value: T) =>
({kind, value})
// ================================
// The map (aka: Functor)
// ================================
// curied version
const map_ =
<KB extends string>(unit: Unit<KB>) =>
<A, B>(fn: (_: A) => B) =>
<KA extends string>(m: Container<KA, A>): Container<KB, B> =>
unit(fn(m.value))
// uncuried version
const map =
<KB extends string, KA extends string, A, B>
(unit: Unit<KB>,
fn: (_: A) => B,
m: Container<KA, A>): Container<KB, B> =>
unit(fn(m.value))
// ================================
// Use
// ================================
// Box now is a polimorphic nominal type constructor
const Box = Unit("Box")
const OtherBox = Unit("OtherBox")
// example
const boxedString = Box("hello world")
const boxedNumber = Box(10)
// Functor map can't fail now
const mapbox = map(Box, (x:number) => x * 2, Box(3))
const mapOtherBox = map(OtherBox, (x:number) => x * 2, Box(3))
// You can use partially aplied version
const mapBox_ = map_(Box)
const mapOtherBox_ = map_(OtherBox)
// Use of curried version
const mapped = mapBox_((x:string) => x + "world")(Box("hello"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment