Skip to content

Instantly share code, notes, and snippets.

View briancavalier's full-sized avatar

Brian Cavalier briancavalier

  • Pittsburgh
View GitHub Profile
type Tuple<Iterables extends Iterable<any>[]> = {
[K in keyof Iterables]: Iterables[K] extends Iterable<infer A> ? A : never
}
export const product = <Iterables extends Iterable<any>[]>(...t: Iterables): Iterable<Tuple<Iterables>> =>
t.length === 0 ? [] : prod(t, [])
export function* prod<Iterables extends Iterable<any>[]>([h, ...t]: Iterables, r: any[]): Iterable<Tuple<Iterables>> {
if (t.length === 0) for (const a of h) yield [...r, a] as Tuple<Iterables>
else for (const a of h) yield* prod(t, [...r, a]) as Iterable<Tuple<Iterables>>
@briancavalier
briancavalier / 1-echo-console.ts
Created February 7, 2020 13:36
Two ways to use Env
import { co, unsafeRun, resumeLater, resumeNow, use, Resume, op } from '../src'
import { EOL } from 'os'
import { createInterface } from 'readline'
type Print = { print(s: string): Resume<void> }
const print = (s: string) => op<Print>(c => c.print(s))
type Read = { read(): Resume<string> }
const read = op<Read>(c => c.read())
@briancavalier
briancavalier / typescript-strongly-typed-variadic-2.md
Last active October 12, 2023 18:34
A technique for strongly-typed, heterogeneous variadic function types in Typescript

Simpler Variadic Function Types in TypeScript (part 2): Higher-order Variadic Functions

In part 1 we looked at a technique that allows expressing strongly-typed variadic functions in a way that solves problems with the current most common approach. It reduces code size and repetition, and it scales to any arity.

I mentioned that the technique can also be extended to higher-order variadic functions, such as the typical zipWith. Let’s explore how to do that.

ZipWith Example

As we did in part 1, let’s start with an example, a typical zipWith on arrays.

@briancavalier
briancavalier / typescript-strongly-typed-variadic-1.md
Last active October 12, 2023 18:34
A technique for strongly-typed, heterogeneous variadic function types in Typescript

Simpler Variadic Function Types in TypeScript (part 1)

Variadic functions, such as the common zip function on arrays, are convenient and remove the need for lots of specific arity-function variants, e.g., zip2, zip3, zip4, etc. However, they can be difficult and tedious to type correctly in TypeScript when the return type depends on the parameter types, and the parameter types are heterogeneous.

Zip Example

Given a typical zip on arrays:

const a: number[] = [1, 2, 3]
@briancavalier
briancavalier / fx.ts
Last active March 17, 2019 23:55
Small encoding of algebraic effects in Typescript (probably works in Flow, too, with syntax tweaks) used in helicopter: https://github.com/briancavalier/helicopter/blob/master/packages/core/src/fx.ts
export type Cancel = void | ((k: (r: void) => void) => void)
export const runCancel = (c: Cancel, k: (r: void) => void): void =>
c ? c(k) : k()
export type Fx<H, A> = (handler: H, k: (a: A) => void) => Cancel
export type Pure<A> = Fx<{}, A>
export const handle = <H0, H1, A>(fx: Fx<H0 & H1, A>, h1: H1): Fx<H0, A> =>
(h0, k) => fx({ ...h0, ...h1 } as H0 & H1, k)
@briancavalier
briancavalier / type-list.js
Created April 6, 2018 13:46
Flow type-level lists
// @flow
// Type-level lists
type Empty = []
// Type-level tail function
type Tail<L> = $Call<FTail, L>
interface FTail {
(Empty): Empty,
<H, T>([H, T]): T
@briancavalier
briancavalier / type-nat.js
Last active August 19, 2018 02:02
Flow type-level naturals and addition
// @flow
// Type-level naturals
type Zero = 0
interface Succ {
<N>(N): [1, N]
}
// Hey look, we can do type-level pattern matching
@briancavalier
briancavalier / lazy-pair.js
Last active October 12, 2017 13:23
Fun with a Lazy type and pairs
// Pair helpers
// Map the first element of a pair
const first = <A, B, C> (f: A => B, [a, c]: [A, C]): [B, C] =>
[f(a), c]
// Map the second element of a pair
const second = <A, B, C> (f: B => C, [a, b]: [A, B]): [A, C] =>
[a, f(b)]
@briancavalier
briancavalier / except.js
Last active September 7, 2017 15:52
A simple Either with added exception semantics, like Haskell ExceptT
// @flow
import { curry2, curry3 } from '@most/prelude'
export type Except<E, A> = Exception<E, A> | Result<E, A>
export const result = <E, A> (a: A): Except<E, A> =>
new Result(a)
export const throwError = <E, A> (e: E): Except<E, A> =>
new Exception(e)
@briancavalier
briancavalier / esnextbin.md
Created May 2, 2017 01:36 — forked from TylorS/esnextbin.md
esnextbin sketch