TypeScriptで関数合成をする関数を書いてみた

関数型プログラミングといえば関数合成みたいなところありますよね。Haskellだと.でagdaだとoだった気がする。

最近やっているTypeScriptで関数合成をやってみました。

以下はググって出てきたこのサイトを参考にしています。 minaluke.medium.com

まず例題のために簡単なInterfaceを定義してみます。 nameというフィールドがあってstringが入っています。

interface IPerson {
  name: string;
}
const person: IPerson = {
  name: "Mina",
};

ここから次の関数を順に実行することを考えます。 処理としてはgetNameでIPerson型からnameのstringだけ取り出して、その結果をgetLengthに流して文字列長を取得。 その結果が偶数かどうかを判定する感じですね。

const getName = (p: IPerson) => p.name;
const getLength = (str: string) => str.length;
const isEven = (num: number) => num % 2 === 0;

合成関数使わずに純粋に書くとこんな感じだと思います。

console.log(isEven(getLength(getName(person))))

これでも良いんだけど関数が多いと書くのがしんどい!!!! ので合成して一つの関数にまとめることを考えます。

そこで関数合成をする関数composeを考えます。 Javascript的な型を考えないと次のようなコードになりそうです。

const compose = (...fns) => arg =>
      fns.reduce((composed, f) => f(composed), arg);

引数として関数の配列fnsを受け取って、reduceで部分適用して進めていく感じですね。 これをTypeScript化することを考えると、fnsargに型を指定する必要があります。 それで実際に書いてみると次のようになりました。

const compose =
  (...fns: ((arg: any) => any)[]) =>
  (arg: any) =>
    fns.reduce((composed, f) => f(composed), arg);

...fnsは「なにかしらの引数を受け取って何かしらの返り値を返す関数 ( (arg:any) => any)の配列」なので((arg: any) => any)[]となり、arg自体は何かしらの型なのでanyになります。 書いてみるとまぁそうだよねという感じですね。多分いい感じのライブラリがありそうなので情報お待ちしております。