fp-ts 2.8.0 で追加された bind, bindTo について
Tags: fpts, haskell, typescript, monad
Published: 2020-08-23 10:34:55

---

title: fp-ts 2.8.0 で追加された bind, bindTo について
published: true
description: fp-ts-contrib の do notation に代わって、fp-ts 2.8.0 で各種の Monad に追加された bind, bindTo の使い方や意義についてまとめました。
tags: fpts,Haskell,TypeScript,Monad
//cover_image: https://direct_url_to_image.jpg
---

## tl; dr

- fp-ts-contrib の do notation に代わって、fp-ts 2.8.0 では `Option`, `Either` などの各種の Monad に `bind`, `bindTo` というメソッドが生えた。
  - [CHANGELOG](https://github.com/gcanti/fp-ts/commit/6dadfc3bf132bfef8a89c9ac8957184296ffe74d)
  - fp-ts-contrib の依存なしに、do notation 的なコードがかけるようになった
- do notation と同様に、`bind`, `bindTo` を使うことで複数の Monadic な値の計算でコールバックによりネストが深くなる問題を解決できる。

## do notation

PureScript など、一部のプログラミング言語には do notation と呼ばれる記法があります。[PureScript の公式ドキュメント](https://github.com/purescript/documentation/blob/master/language/Syntax.md#do-notation)からコード例を引用します。

```haskell
maybeSum :: Maybe Number -> Maybe Number -> Maybe Number
maybeSum a b = do
  n <- a
  m <- b
  let result = n + m
  pure result
```

`maybeSum` は `Maybe Number` な値を 2 つ取って、和を求めて `Maybe Number` で返す関数です。`do` キーワードを使うと、その下のブロックでは例えば `n <- a` と書くことで `Maybe Number` な `a` を `Number` 型の変数として `n` に束縛できます。これの何が嬉しいかは、do notation を使わなかった場合の例を考えるとわかります。

```haskell
maybeSum :: Maybe Number -> Maybe Number -> Maybe Number
maybeSum a b =
  bind a \n ->
    bind b \m ->
      let result = n + m
      in pure result
```

`bind a \n ->`, `bind b \m ->` によりネストが二段深くなってしまいました。do notation を使った場合のコードとプログラムの内容が同じであるとすると、`bind`キーワードがどのようなはたらきをするかは直感的にわかるでしょう。今回の Post において重要なことは、「do notation を使うことで `bind` を使わずに済んでいる」、ということです（もしくはその逆）。PureScript の公式ドキュメントでは、`bind x \a -> ...` が `a <- x` の糖衣構文であることが明記されています。

> `a <- x` which desugars to bind `x \a -> ...`

## fp-ts における do notation

話を PureScript から TypeScript というプログラミング言語に移します。TypeScript には標準で Monad や do notation のサポートがありません。しかし、 [gcanti/fp-ts](https://github.com/gcanti/fp-ts) などのライブラリを利用することで Monadic なコードが書けるようになります。

ただ、do notation については [gcanti/fp-ts-contrib](https://github.com/gcanti/fp-ts-contrib)という別パッケージに切り出されていました。fp-ts-contrib が提供していた `Do` 、次のようにして使われていました。

```typescript
import { Do } from "fp-ts-contrib/lib/Do";
import { option, some } from "fp-ts/lib/Option";

const result = Do(option)
  .bind("a", some(1))
  .bind("b", some(2))
  .return(({ a, b }) => a + b);
```

ここからようやく本題に入っていくのですが、上記のコードが fp-ts 2.8.0 からは以下のように書けるようになりますよというのが今回共有したかった話です。

```typescript
import * as O from "fp-ts/lib/Option";
import { pipe } from "fp-ts/lib/function";

const result = pipe(
    O.bindTo("a")(O.some(1)),
    O.bind("b", () => O.some(2)),
    O.map(({ a, b }) => a + b)
  );
}
```

`Option` などの各モナドごとに `bind`, `bindTo` が提供され、 `fp-ts-contrib` に依存せず do notation 的なコードが書けるようになりました。

`O.bind("b", () => O.some(2))` を `O.bindTo("b", O.some(2))` と書きたくなりますが、[`O.bind` と `O.bindTo` は引数の取り方が違う上、`bindTo` では pipe で流れてくる `Option<A>` の `A` の情報を引き継ぐことができません。](https://github.com/gcanti/fp-ts/commit/6dadfc3bf132bfef8a89c9ac8957184296ffe74d#diff-3cdd78ed006796ba7e0f8a4b642ddf52R1148)（`{ a: O.some(1) }`を引き継ぐことができない）

上記のコードのようなケースでは、 `bindTo` もしくは `bind` を pipe の先頭で使い、以降は `bind` で繋いでいくという方針で書いていくと良さそうです。

## おわりに

この記事はアルバイト先の[株式会社 HERP](https://tech-hub.herp.co.jp/) のまざっちさん（[@mazamachi](https://github.com/mazamachi)）に勧められて書きました。また、まざっちさんには執筆の上でのアドバイスをいただきました。ありがとうございます 🙌

HERP では、TypeScript の高度な型システムや fp-ts などの関数型プログラミングのライブラリを駆使して、混沌とした Web フロントエンドの世界をともに生き抜いていくソフトウェアエンジニアを[募集しております](https://herp.careers/v1/herpinc/CrMCGkcKbpNA)。オフィスは東京・京都・つくばにあってフルリモートも多分可能です。いい会社です！