11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScriptAdvent Calendar 2019

Day 9

TypeScriptで関数合成するライブラリをつくった

Posted at

表題のとおりで、fp-minimalというライブラリを作りました。

モチベーション

まず例として、メールアドレスとパスワードを入力するログイン機能を考えます。それはおそらく、以下のように書くことができます。

import { pipe } from 'fp-minimal';

const login = pipe(validate, getToken, responseToState, redirect)

このように、小さな関数(validate, getToken, responseToState, redirect)を組み合わせて機能を作る際に、可読性を上げることができます。

概要

fp-minimalのAPIはpipecurryのみで、サイズも約1.6KBとなっています。
(composeをつくらなかったのはminimalという名を守るため)。

Ramdaのようなライブラリを入れると、全てをRamdaでなんとかしようとしてしまい、場合によっては効率の悪いコードを書いてしまうときもあるかもしれません。愚直に小さい関数を組み合わせてアプリケーションをつくりたいというだけなら、これらのAPIで十分である、というのが想いです。

実装

小さいので、コードの中身を紹介します。

pipe

export function pipe(...args: Function[]): any {
  // reduceRightにするとcomposeになる
  return (input: any) => args.reduce((result, next) => next(result), input);
}

curry

export function curry(func: Function) {
  return function curried(...args: any[]) {
    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      return function(...args2: any[]) {
        return curried.apply(this, args.concat(args2));
      };
    }
  };
}

型は力技…。

export function curry<T1, R1>(func: (a: T1) => R1): (a: T1) => R1;
export function curry<T1, T2, R1>(func: (a: T1, b: T2) => R1): (a: T1) => (b: T2) => R1;
export function curry<T1, T2, T3, R1>(func: (a: T1, b: T2, c: T3) => R1): (a: T1) => (b: T2) => (c: T3) => R1;
export function curry<T1, T2, T3, T4, R1>(func: (a: T1, b: T2, c: T3, d: T4) => R1): (a: T1) => (b: T2) => (c: T3) => (d: T4) => R1;
export function curry<T1, T2, T3, T4, T5, R1>(func: (a: T1, b: T2, c: T3, d: T4, e: T5) => R1): (a: T1) => (b: T2) => (c: T3) => (d: T4) => (e: T5) => R1;

使用例

使う時はこのように

import { pipe } from 'fp-minimal';

const double = (x: number) => x * 2;
const addOne = (x: number) => x + 1;
const square = (x: number) => x * x;

pipe(double, addOne, square)(2) // 25
import { curry } from 'fp-minimal';

const add = (x: number, y: number) => x + y;
const addOne = curry(add)(1);

addOne(2); // 3
[1, 2, 3].map(addOne); // [2, 3, 4]

型も推論されています。

スクリーンショット 2019-12-13 23.29.01.png

返り値の型が変わる場合

スクリーンショット 2019-12-13 23.32.36.png

curry

スクリーンショット 2019-12-13 23.35.45.png

curry化した関数で新しい関数を作った場合

スクリーンショット 2019-12-13 23.33.31.png

おわりに

小さいパーツつなぎあわせてソフトウェアを動かすのは楽しいですね。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?