TypeScriptの動かせるコードで型クラスを理解する(Semigroup, Monoid, Functor)

## やりたいこと

TypeScriptにおける**型クラス**(Type Class) について整理したい。

- 断片的なコードでは理解が難しいので、[TypeScript Playground](https://www.typescriptlang.org/ja/play)で動かして試せるコードを用意する
  - リンクを開いて「実行」を押せばすぐ結果が表示される
  - 誰でもコードを改変していろいろ試すことができる
- 長くないコードで比較的理解しやすい**Semigroup, Monoid, Functor**について扱う
  - これらはTypeScriptに限らず、関数型プログラミングでは一般的な概念
- Haskellや圏論等由来の用語はなるべく使わない
  - 厳密さや網羅性は犠牲になっている

## TypeScriptにおける型クラスとは

任意の型 `A` に対して、「こんな操作ができるよ」と定義した「型」。

## 型クラスの実例1 Semigroup

[サンプルコード SemigroupSample.ts (TypeScript Playground)](https://www.typescriptlang.org/ja/play?#code/PTAEDMAcFoBcGdQGUCmBbAlgcwE4HsBXSUAC1lkngC4QsBjAQwDtYMA6LDWEggIzYx5gUOPGBo8AEwIAbFGNSZchSGwRsyaGQChtIZOmz4ioQHYMgaPVA9QyBLhkCdDHrCBvuUDwhhdAADAILvQgawZAf9qA6gyAZgyAMAyACr6AECqAEP-udHhMjLDugJD-gDIMgOYMgLIMgNEMgBEMgLAMgBYMgFnagJX+gYD6DKHmBdoYLCg44Ax0KAZKxpAAPJ4AfKAA3tqgoDgoDJIJMgCeoPGJDLBUoAAUAB4rngA0oDNbAJSgALwDntoAvrr6ikYqoIAlDIDPDLaA-QwvDqDwsDgNWH5BMJRWILJKpTK5QqlCrVZ5vF51BbfL6GZREJA-P4rW5onrfX5MLADY5DEbzBJJFYbXYzI6nUDrUAAaj220u2ngqK6GIJWDYoKWqwA5CQ8FgUELdkLwAQsAwhUd9KLxTK5dcwHD3rZAEkMgB15HJFLKAQAYIpECoB7BiigFWbQDiStrAAF2lUAmgyAUf1AIGRaUAQgw5DlclQ8v78imCkViiW7Tmdf2YwlBxawYWq+VSyAYGZ4BWKsDKlBJ1Pp31R9ExvkChORu7F3lxpLCnOS0DS2Xyg4ptMZrOkMN59vq0BMAhoXhNAEhU0g4PJdLZfLFcpVUKahHaJGwFFFyAAOUHw5wnkkkmxfqI3QHQ6axNJozLVPWNLpA0ZLJmbKuFdx2-Pe4PNcFAEYAAZdgAJgAzsAGYAL7U0LUAAqVAHTvDJACsGQB5BmCQAghmtO1HUAbQZAAcGQARBgIlcEmRd8uk-XcAFlZFYSBZiPDdTx3C8Tivcl41ve8TkfUAACpWXZciVEopoaJkOjZl-BNAJAsDQH0UCoM+cxzUAVXkMnQojPiolAB1HYJtFgGZIHaXT9JJYZRiYBg0BQFZ8T+MlIF+NoVjPXcFLAQAwxTJRgZDwX57P7FicC80AAGt-LJeA8Ak9zQvCrB2VXddK0gcyCEY9Lukyy8rI4yk1jvPYH3Y0ZxlgAgcCYcrRn7WzgvWNgbLs5lGyKIV2pmFrGrZer6pcjA3IZNghrabqxtclB+oG+YGACoKVma-zAowdpn35Ba1pmskBti+LRoOtdNuO2bRiuC7X10VKsDwEhmBWTK2IK1rgqFQAVBkAe4zJWc6aVj-UDZtWpbQHAyDZuOlYgJS0i10wWL4BIDAcCy0Bnsssk3pWIVAGcVQAZNUAQRtftGcbgoADhh69ttB4CAFZIbi5ZQD-NgGdhphkQihgcAYBhxSevSCBerHGpxwAEVUALeNACUGEnQDJlZ6ap+bFvWlZwLp5WobB67hKITLpNWO6HqYXYEbwJGUYITtBgauyce+ooCeJ3YQbVsG6YZr4mYBtmrk+HEulADJPUAGIY8KQwBkhk0wB1hkAK4YnkACYYZ0AItTAAdTPVQ59GVElYBJ5YJWBbl6PpVgrbLcRLg5by2GlDh40AADc8AwSR2Mq6raupUqG6ROKUDYAKsDLwxDZK2kDnZbQhpYW4R43ANCQOOswwbJs5QVcKcyTafC7nvWt1C-dJGX2TQFAiCoJnovDHn9LRJwcTJNpVYz4v8KlN3hob8wO-cUy5eB8DZliNvdZgZsMCI2RqjVskUeZ83FJPAa+hbYACI3qoJWKgx2zsihS2lqg3YqCyaYNAAAFk1kQt2KBSEAHYAJe1QcdUhZC2agAuKAbQQA)

### Semigroupの型クラス

任意の型 `A` に対して「結合（`concat`）ができるよ」と定義した「型」。

```typescript:SemigroupSample.ts
interface Semigroup<A> {
  readonly concat: (x: A, y: A) => A
}
```

### Semigroupのインスタンス（string編）

型クラスを「任意の型」で実現したものを**インスタンス**と呼ぶ。
以下はstringに対して「結合（文字列連結）ができるよ」と定義した「インスタンス」。

```typescript:SemigroupSample.ts
const semigroupString: Semigroup<string> = {
  concat: (x, y) => x + y,
}
```

以下のように使うことができる。

```typescript:SemigroupSample.ts
semigroupString.concat('hoge', 'fuga') // hogefuga
```

Semigroupの「結合」は、以下のように結合法則を満たす。
これはインスタンスを作る側が動作を保証する必要がある。

```typescript:SemigroupSample.ts
semigroupString.concat('hoge', semigroupString.concat('fuga', 'piyo')) // hogefugapiyo
semigroupString.concat(semigroupString.concat('hoge', 'fuga'), 'piyo') // hogefugapiyo
```

### Semigroupのインスタンス（number編）

以下はnumberに対して「結合（加算）ができるよ」と定義した「インスタンス」。

```typescript:SemigroupSample.ts
const semigroupNumberAdd: Semigroup<number> = {
  concat: (x, y) => x + y,
}
semigroupNumberAdd.concat(10, 20) // 30
```

「結合」の処理は、結合法則を満たす処理なら何でもよい。
以下はnumberに対して「結合（乗算）ができるよ」と定義した「インスタンス」。

```typescript:SemigroupSample.ts
const semigroupNumberMultiply: Semigroup<number> = {
  concat: (x, y) => x * y,
}
semigroupNumberMultiply.concat(10, 20) // 200
```

### Semigroupのインスタンス（独自型編）

例えば以下のような`Menu`型があったとする。

```typescript:SemigroupSample.ts
type Menu = {
  name: string
  price: number // 円
  calorie: number // kcal
  solt: number // g
}
```

「結合」の操作が可能な型なら、Semigroupのインスタンスを作ることができる。
以下は`Menu`に対して「結合（メニューのまとめ？）ができるよ」と定義した「インスタンス」。

```typescript:SemigroupSample.ts
const semigroupMenu: Semigroup<Menu> = {
  concat: (x, y) => {
    return {
      name: x.name + 'と' + y.name,
      price: x.price + y.price,
      calorie: x.calorie + y.calorie,
      solt: x.solt + y.solt,
    }
  },
}
```

これは以下のように使うことができる。

```typescript:SemigroupSample.ts
const gohan: Menu = {
  name: 'ご飯',
  price: 120,
  calorie: 330,
  solt: 0,
}
const misoshiru: Menu = {
  name: '味噌汁',
  price: 80,
  calorie: 25,
  solt: 1.5,
}
const karaage: Menu = {
  name: '唐揚げ',
  price: 250,
  calorie: 350,
  solt: 3,
}
semigroupMenu.concat(gohan, misoshiru) // { name: 'ご飯と味噌汁', calorie: 355, solt: 1.5}
```

### Semigroupの共通処理

ここまで見たとおりSemigroupであれば、「任意の型」を2つ「結合（`concat`）」に渡せば、「任意の型」が返ってくる。
このため「任意の型」が何なのかに関わらず、共通に使える処理を書くことができる。

```typescript:SemigroupSample.ts
function printSemi<A>(semi: Semigroup<A>): (x: A, y: A) => void {
  return (x, y) => console.log(semi.concat(x, y))
}

printSemi(semigroupString)('hoge', 'fuga') // hogefuga
printSemi(semigroupNumberAdd)(10, 20) // 30
printSemi(semigroupNumberMultiply)(10, 20) // 200
printSemi(semigroupMenu)(semigroupMenu.concat(gohan, misoshiru), karaage)
    // { "name": "ご飯と味噌汁と唐揚げ", "price": 450, "calorie": 705, "solt": 4.5 } 
```

## 型クラスの実例2 Monoid

[サンプルコード MonoidSample.ts (TypeScript Playground)](https://www.typescriptlang.org/ja/play?#code/PTAEDMAcFoBcGdQFkD2A7FBLAJqAFrLJPAFwgDmAxgIZqyYB05mseArgEYOYrBRzxgAWxTY2AGwCmg1BhwMEDAkPEAoVSGTosuQPYMoAMqShmcgCcUbSKEDWDIENzQG9ygGQZA6RqAJBkD6DICCGQHYMqzHSSZuDUlJKGxqYWVgA8AIIAfKAA3qqgoGaS1Njo4gCeoJToNLAkoAAUAB5lcQA0oHk1AJSgALxJcaoAvuqasjqgPoDR6oD1DICXDICdDBpggN9ygPCGw6AABnFLtoB-2oDqDIBmDIAwDIAKvoAQKoAQ-0tFaCVLgJD-ToDmDICyDIDRDIARDICwDLuAX+qANOY+gCQKp8ZILA8tcnIAhBher0AFgyALO1AJX+mw8uyGr38gWCoXC-Rw8SSkkqsEkaGwiCMJnMlkguJSaQyWRyaHyoEBwJq3V6YGxuEAJQyAZ4YJoB+hn501A8FgZgC5A2OwOJzOxWosFBD0hnx+-0AXl6AcNNAOraNwhb1hCKRfMF-NR5zFoBEcmwBnFkrKXJiYolaHISVaNPS5xKZSq9TyLXaoEqoAA1A1arSWY1QAByePRnoi01CiaAJIZADryjyh90AgAxqv6vXSASwYfIAwDMAVq63QCq8oAyvVlrx2XnzgAtFQDK8j59oAc810gEhNQDxDIBIhkAVgyAEQZnoAxBlHvxsgE0GR6AUf1AIGR4MeqhtOntbvIDF9ivK8bwKHIkiT1u0OB3koYsaam6vdod7v3Ctg5S315fe9j9WPp7ng+X7Prub4XIetIgTer5-lBT4wXuB4fgBZ4XtBP53kIQJBqoD4iqOPi3IADqa-D4gAsGoc+aAAVKgDp3lCgDqcrRty6EWvyvE4gCqCVOqiWrAl62gAcmwQgcEEcTYNgTpPjEaAiWJZiet6hTvv6lSBsGSRhpGeTRuksZlAADMmvHoFaIHCaJQRIBI9CQPk0m2rJ8lBEpqQ+qpFTqQ0mmhqAABUUYxthrKgAAjCZIqAMoMPiAIcMgDTDIApwyAD8MFGHLouqAOhKPiAMQJ+w2IAFzZzKowKQFiRJsG0ynpGg1BCJIZSupKtLpJAEphGUclWWYoCaIAYYotYU1DiCgEoNaAXUKb1YAANY0Go6TpPAKDiKUE0uT1mjkLSPR8QJOhIBVjk6DEh1yW5tLIWpGltEk7mLZksBsGYaDVYttX1WUlQMB9kgMFI7qsG0rReoZoAAPwND9dXhF90P1RGCZQvGiN5PDkh6YtrXteN31tZgYSoww+NhJjWPzaNmC4-uw2U+EOk0yNY1k4ty2rXDbP8QznMsz06RdJjBlvb9ZSJizJPjcZg0U2NRks5zcs7ZFmhsRxEJQrsbaABcJGaAPIMgDGDIAJgyAIoMjyvKO5aAGeKgBgLk4WaAFEMgAhDPOuujhu4BsBc9DoCpEGwHE4jiLin5PsdOKJE0-rUGYZjUHGcQx3HuK+XEymPc9r3lNHsdBrdoDZ3HDCZGIYQh7a4ElPUIFYThD4ppaK1-SN5DlMhAfiGX24-k05QANqoee-4e+Q1AXvGkCYHkKDxgAuk0LSaCeZ7D9QE9T6ZaBs03p6t++7edzglkKRJ2A973YXGaAABMl8AMyGXPC9gAAbIZG9b-9O9t4HB-YEf1m2UwPZIMfcL71BvvUe+9QAAsD957TWvrAwyyD1B7XICgPAtAnQVSqvdGqMNRaABUGQA9xlJkGhLMoYUIHS1prLUAt8oGDQVqAKW-NLpmX4iYZa8A8CYDMGwbBclcGDRFgmQAziqABk1QAgjZkKxhQ0AAAOVhi0ZZUzKFfAArPLFaa0woMC0Ttdhm9+IzWjtQagZ5BGVS9HgiaBCEyAARVQAW8aACUGWRi15GaOUT6Whaj6EaO8aKHRZRb6Y12hw0Uw1shWOEfgz6CZACtDGMQAAwzuPkWFAJmNVHjVfpjZhhkGDQMig3KQn8W7fw7iBM6bAz7oMwWgKumBuG8P4fUUxscLEY0ieIbIj9BqaGSKAAARL9IZZQhkkKhJIqRUJnEuKhEk5JQz6hDIlmM0Ar9L5DOyesgA7M-LRwzObrOgQwAAnKALooBVBAA)

### Monoidの型クラス

任意の型 `A` に対して「結合（`concat`）ができるよ」「基本の値（`empty`）があるよ」と定義した「型」。

```typescript:MonoidSample.ts
interface Semigroup<A> {
  readonly concat: (x: A, y: A) => A
}

interface Monoid<A> extends Semigroup<A> {
  readonly empty: A
}
```

MonoidはSemigroupに「基本の値」というルールが増えたもの。
このためSemigroupをextendsして定義している。

### Monoidのインスタンス（string編）

以下はstringに対して「結合（文字列連結）ができるよ」「基本の値（空文字）があるよ」と定義した「インスタンス」。

```typescript:MonoidSample.ts
const monoidString: Monoid<string> = {
  concat: (x, y) => x + y,
  empty: '',
}
```

インスタンスを作るとき、「基本の値」は「どの順番で何度結合しても、全体の結果は変わらない」ような値にする。
これもインスタンスを作る側が動作を保証する必要がある。

```typescript:MonoidSample.ts
monoidString.concat('hoge', monoidString.empty) // hoge
monoidString.concat(monoidString.empty, 'hoge') // hoge
monoidString.concat(
  monoidString.empty,
  monoidString.concat('hoge', monoidString.empty)
) // hoge
```

### Monoidのインスタンス（number編）

以下はnumberに対して「結合（加算）ができるよ」「基本の値（`0`）があるよ」と定義した「インスタンス」。

```typescript:MonoidSample.ts
const monoidNumberAdd: Monoid<number> = {
  concat: (x, y) => x + y,
  empty: 0,
}
```

以下はnumberに対して「結合（乗算）ができるよ」「基本の値（`1`）があるよ」と定義した「インスタンス」。

```typescript:MonoidSample.ts
const monoidNumberMultiply: Monoid<number> = {
  concat: (x, y) => x * y,
  empty: 1,
}
```

このように、型と処理によって「基本の値」は変わってくる。

### Monoidのインスタンス（独自型編）

以下は`Menu`に対して「結合（メニューのまとめ？）ができるよ」「基本の値（空のメニュー？）があるよ」と定義した「インスタンス」。

```typescript:MonoidSample.ts
const monoidMenu: Monoid<Menu> = {
  concat: (x, y) => {
    return {
      name: x.name.length === 0 ? y.name : x.name + 'と' + y.name,
      price: x.price + y.price,
      calorie: x.calorie + y.calorie,
      solt: x.solt + y.solt,
    }
  },
  empty: {
    name: '',
    price: 0,
    calorie: 0,
    solt: 0,
  },
}
```

### Monoidの共通処理

Monoidは「基本の値」があるため、「全部をくっつける」などの処理が作りやすくなる。

```typescript:MonoidSample.ts
function concatAll<A>(monoid: Monoid<A>): (array: Array<A>) => A {
  return (array) => array.reduce(monoid.concat, monoid.empty)
}

console.log(concatAll(monoidString)(['hoge', 'fuga', 'piyo'])) // hogefugapiyo
console.log(concatAll(monoidNumberAdd)([10, 20, 30])) // 60
console.log(concatAll(monoidNumberMultiply)([10, 20, 30, 40])) // 240000
console.log(concatAll(monoidMenu)([gohan, misoshiru, karaage, salad]))
    // { "name": "ご飯と味噌汁と唐揚げとサラダ", "price": 600, "calorie": 765, "solt": 4.9 } 
```

## 型クラスの実例3 Functor

[サンプルコード FunctorSample.ts (TypeScript Playground)](https://www.typescriptlang.org/ja/play?#code/PTAEDMAcFoBcGcIFcB2BjWB7ATqAFrLJPAFwgDmaAhirAJYB05dseSARg3ZsFHPMAC2mACZIANgFMBAMVQYcDBAwKDxAKHUhQc9FlyA7BkDR6oHqGQJcMgToYtYQN9ygeENjoAAYynoQNYMgP+1A6gyAzBkAwDICq8oCRDIDSDAaAZ4qAYC6AEP9OglSQToCQ-4AyDIDmDICyDIDRDIARDICwDIAWDIBZ2oCV-t6A+gz+RvnWoJIAHpA4sKB0tJLY4FRokjry+gA8MgB8oADedaCg2JJUIpgo4gCeoAmQJKCDAIIANKAAQiMAFN2bMjsj++Cbx1Sb2wCUoAC8YwfPbzqDR3UAvpptIADBlSgCg5QAYUYB7BkAzQyAZ4ZAIsMgBKGQDXDIAKhjMgB+GdyAKwZsjEACrLSCSADKaGwdEgrXS322Y0KgBEGQBiDODAA-xkKy2IZyTqfAQoHSkMAp3KAaDkDLkmdjAKe6gGpNQBJDH5aWM5YB87UAf85+BnZXkwfkACQA0vj8IRiGRgJQaPQmCw2JxuLxdQJhGIpAJDfilPAVLA1HVAMoM-sFgBj9QBZvgZQABZZYAeSp3BQoDlgFWlUKATQYgYBFBgMgAZfKUK3xazRoRbwVoAVQASgBJV6gADk0bj9EW9c0sCJfSrtZeoA7xMw4FA3c07VgnW6vVAHsG3f2dIm6mms3mixWoAA+t3NiPl3MFktVhvtg91AD1GOJz0uzWsAb2iJLou96vD6AANrdgC6myb8cWlxnu2nbDjWJJ1gA1pIyyDqB1Z3g+gw0MsIzAcSoD3igj7dvUDTjlhiDdiS85jL2OGNPhIiEWBoAAPxwQhWGXJ+NZfqAmzIYCYCAJymgCBDL4-R6DgoDGOYVjaPYjguG4Xh+EEYSRLE8SJCkGQ5AUJTlFUNQXh0XTXoJCjYMMuGUdR1YkmMkwvge67bjoS4zPua6rOsmw7PsRynPcGGITIJHXLcPlPK87yfGMmGPv5hyoee2iACQKqSAEIM2ShIAQQxculcqABYRaZRrG-6JkYcplGm2r9n0AByix9L24ybrAVDkJs9YoDV9agACFWgCSmCCJIT51Q1TUtfAfWSPW+wAG5UOISCSA8nXqN1f4tigg2gNVKB9AAPj142AXUuhGaAiKwhYgD9DOddSrQmHg+AEIThNEcTrKpWR5EUZSVP4Z2XedtQligZbIEJ2C3Ys5wDDgs41qRz5wbsjluVsewxd5v4FWtlyBaAdwPOFhyPJjzYJj8pFWY50zaP6BiACwagAQKpCQShN4wSJUlgAxDIADgzHGN-WPIAcHKABIMwScxUgBFqYADqanI8ilymVBSgIUuJU05sBINgibdAwG6NeQrwvL29b8xNavTPR9V6yNDam5NoAzXNC0QN5DCO-NzwAtM3vsRAVCOQC55AyDmBUie+WkwB21TZ08NW-rLVtdtHUAsHrSh7ABwk4VgxlhSKDkHHw3Nbb432+7zv1ngmDkJI1e1ynxalpgUgMOINenND4NYwmDDrMcGdo3zmx5+05CE96UgF6wjzPNo8c2617VLcHLeSG3HfgF3EMoH3iQD1SBz7MPoCjwXE9t5I094LPoDz8Xo1l9Ns3zZsAAcS2aEAA)

### Functorの型クラス

任意の型 `F` に対して「何らかの処理（`map`）ができるよ」と定義した「型」。

```typescript:FunctorSample.ts
export interface Functor<F> {
  readonly map: <A, B>(fa: F<A>, f: (a: A) => B) => F<B>
}
```

イメージは上の通りだが、上のコードはエラーになる。
TypeScriptでFunctorを実現するには一工夫が必要。
（詳細はサンプルコードを参照）

工夫した結果は以下の通り。

```typescript:FunctorSample.ts
interface Functor<F extends URIS> {
  readonly URI: F
  readonly map: <A, B>(fa: Kind<F, A>, f: (a: A) => B) => Kind<F, B>
}
```

意味的には最初の通りなので、URIとかKindとかはひとまず無視していい。
「何らかの処理（`map`）」をもう少し噛み砕くと、以下のようなかんじ。

- 型 `F<A>` の値 `fa` を受け取って
- 何かしらの関数 `(a: A) => B` を適用して
- 型 `F<B>` の結果を返す

### Functorのインスタンス

今回の「任意の型」は、「値があるかも、ないかも？」を表す`MyOption`型を定義する。
（一般的なOptionを簡素化したもの）

```typescript:FunctorSample.ts
type None = { _tag: 'none' }
type Some<A> = { _tag: 'some', value: A }
type MyOption<A> = None | Some<A>
```

以下は`MyOption`に対して「何らかの処理（`map`）ができるよ」と定義した「インスタンス」。

```typescript:FunctorSample.ts
const functorMyOption: Functor<URI> = {
  URI,
  map: <A, B>(fa: MyOption<A>, f: (a: A) => B): MyOption<B> => {
    return fa._tag === 'some'
      ? { _tag: 'some', value: f(fa.value) }
      : fa
  }
}
```

これも噛み砕くと、以下のようなかんじ。

- 型 `MyOption<A>` の値 `fa` を受け取って
- 値があれば(some)
    - 何かしらの関数 `(a: A) => B` を適用して
    - 型 `MyOption<B>` の結果を返す
- 値がなければ(none)
    - そのまま返す

これを使い、以下のように「値のある場合だけ処理を実行する」コードを書くことができる。

```typescript:FunctorSample.ts
const optA: MyOption<never> = { _tag: 'none' }
const optB: MyOption<string> = { _tag: 'some', value: 'hogehoge' }
console.log(functorMyOption.map(optA, (s: string) => s.length)) // { _tag: 'none' }
console.log(functorMyOption.map(optB, (s: string) => s.length)) // { _tag: 'some', value: 8 }
```

### FunctorからApplicative, Monadができる

Functorの型クラスに
「値を何かしら処理して任意の型 `F` として返却できるよ(`of`, `pure`)」
の定義が加われば**Applicative**の型クラスになり、
Applicativeの型クラスに
「任意の型 `F` の値と、`A` を `F<B>` に変換する関数を渡して、`F<B>` を返却できるよ(`chain`, `flatMap`)」
の定義が加われば**Monad**の型クラスになる。

```typescript
// Applicative で加わる定義
readonly of: <A>(a: A) => F<A>

// Monad で加わる定義
readonly chain: <A, B>(fa: F<A>, f: (a: A) => F<B>) => F<B>
```

（上記はイメージ、前述のFunctorの定義と同様にエラーになる）
長くなりそうなので別の機会に。

## 参考文献

[TypeScriptの関数型ライブラリ fp-ts](https://gcanti.github.io/fp-ts/)
[Scalaライブラリ「cats」の解説 - Type classes](https://typelevel.org/cats/typeclasses.html)
[TypeScriptと型クラス](https://kazchimo.com/2021/05/29/typescript-typeclass/)
[30分でわかるJavaScriptプログラマのためのモナド入門](https://kentutorialbook.github.io/30minLearningJavaScriptMonad/)