TypeScript

sequenceを作りたかった

きっかけ

「TypeScriptでいい感じのSequenceがほしい〜」
という意見を同僚から頂いたので作ってみようという経緯が書いてある

sequenceとは

リストの中に入ったいい感じの関数が適用できる何かをなんかいい感じのリストにするやつ。
(今回はリストしか扱わない)

一旦Optionalのsequenceを考えてみる

今回は割りと癖のあるOptional

type Optional<T> = [T] | 0

function seqOp<T>(xs: Optional<T>[]): Optional<T[]> {
    return xs.reduce<Optional<T[]>>((acc, x) =>
        acc && x ? [[...acc[0], x[0]]] : 0, [[]])
}

こんな感じになります。

ちょっと抽象化してみる

一旦app関数とSome関数を作る

function app<T, R = T>(f: Optional<(t: T) => R>, x: Optional<T>): Optional<R> {
    if (f && x) {
        return [f[0](x[0])];
    }
    return 0
}

function Some<T>(x: T): Optional<T> {
    return [x];
}

こいつを使うと

function seqOpWithApp<T>(xs: Optional<T>[]): Optional<T[]> {
    return xs.reduce<Optional<T[]>>((acc, x) =>
        app(app(Some(y => arr => [...arr, y]), x), acc),
        Some([]))
}

このy => arr => [...arr, y]部分は任意の実装に対して有効そうな気がしたので、これを使って抽象化する方針で行こうとしていた。

前提として

TypeScriptって型パラメータを必要とする型パラメータを扱えない(これは最初からわかっていた)ので、
function seq<S, T>(xs: S<T>[]): S<T[]>みたいにはならない。

なので抽象化のレベルを落として

type All<T, O> = T | O
function sequence<T, O>(xs: All<T, O>[]): All<T[], O>

っぽいものを作って
「いやぁTypeScriptだとこれが限度ですわ〜〜」みたいなお茶の濁し方で終わろうと最初から企んでいた

なので厳密にはsequenceはできていない

ちなみに上だとfunction sequence<T>(xs: T[][]): T[][]は作れない

最終できたもの

人間が使いやすいようにsequenceGenを作ることにした

type All<T, O> = T | O

type Left = <U>(x: U) => All<U, never>

type Appf = <T, O, R = T>(a: All<(x: T) => R, O>, b: All<T, O>) => All<R, O>

function sequenceGen<T, O>(L: Left, app: Appf)   {
    return function sequence(xs: All<T, O>[]): All<T[], O> {
        return xs.reduce((acc, x) => 
            app<T[], O>(
                app<T, O, (arr: T[]) => T[]>(
                    L<(y: T) => (arr: T[]) => T[]>(
                        (y: T) => (arr: T[]): T[] => [...arr, y]), x), acc), L<T[]>([]))
    }
}

上の型でコンパイルが通った音が鳴った。

これはかなり恐ろしいことで且つ申し訳ないことなんだが、実行していない。ちょっと疲れてしまったので。

もしかしたら、sequenceGenの引数の型を満たすものを実装することができないのかも知れなくて,
sequence関数は僕たちの夢の中にあるのかもしれない

easyな実装方法

たぶん、 (x: T) => x is Sみたいな関数をいい感じに使うともうちょっとそれっぽさが出る気がしているのだが
フローベースコントロールをsequenceの中に入れたくなかったのでやってない。
たぶん、誰かがやってくれるはず。