fp tsから始まる


ポストでは、我々は効果的なプログラムを作成することができます見たf: (a: A) => M<B> 純粋にn -プログラムg 持ち上げるg , 提供M アプリケーションのインスタンスインスタンスを認める
プログラムF
プログラムG
組成
純粋な
純粋なg ∘ f効力のある
純粋なn -アリーliftAn(g) ∘ fどこliftA1 = liftしかし、我々は1つの最後のケースを解決しなければなりません:両方のプログラムが有効であるならば、どうですか?
f: (a: A) => M<B>
g: (b: B) => M<C>
このような「構図」とはf and g ?
この最後のケースを処理するために、我々はより強力な何かを必要としますFunctor 入れ子になったコンテキストで終わるのはかなり簡単ですから.

問題:入れ子になった文脈
もっと必要な理由を説明するために、いくつかの例を見てみましょう.
M = Array )
Twitterユーザーのフォロワーのフォロワーをリトライしたいと言います.
interface User {
  followers: Array<User>
}

const getFollowers = (user: User): Array<User> => user.followers

declare const user: User

const followersOfFollowers: Array<Array<User>> = getFollowers(user).map(getFollowers)
何か悪いところがあります.followersOfFollowers は型Array<Array<User>> でも欲しいArray<User> .
入れ子になった配列を平らにする必要があります.
The flatten: <A>(mma: Array<Array<A>>) => Array<A> 関数のエクスポートfp-ts 便利になる
import { flatten } from 'fp-ts/Array'

const followersOfFollowers: Array<User> = flatten(getFollowers(user).map(getFollowers))
いいね他のデータ構造はどうですか?
M = Option )
数字リストの先頭の逆数を計算したいと言う
import { Option, some, none, option } from 'fp-ts/Option'
import { head } from 'fp-ts/Array'

const inverse = (n: number): Option<number> => (n === 0 ? none : some(1 / n))

const inverseHead: Option<Option<number>> = option.map(head([1, 2, 3]), inverse)
opss、再びやった.inverseHead は型Option<Option<number>> でも欲しいOption<number> .
入れ子を平らにする必要があるOption s.
import { isNone } from 'fp-ts/Option'

const flatten = <A>(mma: Option<Option<A>>): Option<A> => (isNone(mma) ? none : mma.value)

const inverseHead: Option<number> = flatten(option.map(head([1, 2, 3]), inverse))
すべての人々flatten 機能.それは偶然の一致ではなく、フードの下に機能的なパターンがあります.
確かに、これらの型のコンストラクタ(および他の多くの)は、monadインスタンスを認めます

flatten is the most peculiar operation of monads


それで、モナドは何ですか?
これは、モナドがしばしば提示される方法です.

定義
モナドは3つのもので定義されます.
( 1 )タイプコンストラクタM インスタンスを認める
2)機能of 次の署名
of: <A>(a: A) => HKT<M, A>
3)機能flatMap 次の署名
flatMap: <A, B>(f: (a: A) => HKT<M, B>) => ((ma: HKT<M, A>) => HKT<M, B>)
注意:HKT 型はfp-ts ジェネリック型コンストラクタを表す方法ですHKT<M, X> 型コンストラクタと考えることができますM 型に適用されるX (i.e. M<X> ).
関数of and flatMap は三つの法則に従う必要がある:
  • flatMap(of) ∘ f = f (左)
  • flatMap(f) ∘ of = f (正体)
  • flatMap(h) ∘ (flatMap(g) ∘ f) = flatMap((flatMap(h) ∘ g)) ∘ f (結合度)
  • どこf , g , h すべての効果的な機能と は通常の関数合成です.

    しかし、.なぜ?
    私が最初にそのような定義を見た日に戻って、私の最初の反応は困惑でした.
    すべてのこれらの質問は、私の頭で回っていました:
  • なぜ、これらの2つの特定の操作と理由は、これらの種類がありますか?
  • なぜ“flatmap”という名前ですか?
  • なぜ法律?どういう意味ですか.
  • しかし、何よりも、私はどこですかflatten ?
  • この投稿はそれぞれの質問に答えるようにします.
    私たちの問題に戻りましょう:2つの効果的な関数の構成は何ですか?

    (2つのkrouli矢、それらの構成は何ですか?)
    私は、そのタイプが何であるかについて、わかりさえしません.
    …を待つ.我々はすでに、すべての組成についての抽象化に遭遇した.私の言ったことを覚えていますか.

    Categories capture the essence of composition


    我々は、問題をカテゴリー問題に変えることができます:我々はKrestrli矢の構成をモデル化するカテゴリーを見つけることができますか?

    クレーリ族
    カテゴリーk(kdeliliカテゴリーという名前の)を作りましょう.
  • オブジェクトはtsカテゴリの同じオブジェクトです.
  • モーフィズムは、このように構築されていますf: A ⟼ M<B> 我々は矢を描くf': A ⟼ B イン・ケー

  • (tsカテゴリーより上)
    だから、何の組成になりますf' and g' Kで?それは、ラベルの付いた矢印ですh' 下記のイメージで

    (TSカテゴリーの構成より、K構文の構成より下)
    以来h' からの矢ですA to C , 対応する関数h からA to M<C> インTS .
    だから、の組成の良い候補f and g TSでは、以下のシグネチャを持つ有効な関数です.(a: A) => M<C> .
    どうやってこのような機能を構築できますか?さて、試してみよう!

    我々がステップによる構成段階を造る中で
    モナド定義のポイント(1)はM 関数のインスタンスを認めるので、lift 機能g: (b: B) => M<C> 機能するlift(g): (mb: M<B>) => M<M<C>> (ここではシノニムを使いますmap )

    どこflatMap 由来する
    そして、現在、我々は動かれています:タイプの値を平らにすることができるFunctionインスタンスの法的操作はありませんM<M<C>> 型の値にM<C> , 追加が必要ですflatten 操作.
    そのような操作を定義できれば、我々は探している構成を得ることができるh = flatten ∘ map(g) ∘ fでも待ちます.flatten ∘ map(g) フラットマップは、名前がどこから来るのです!h = flatMap(g) ∘ f今すぐ私たちの“組成表”を更新することができます
    プログラムF
    プログラムG
    組成
    純粋な
    純粋なg ∘ f効力のある
    純粋なn -アリーliftAn(g) ∘ f効力のある
    効力のあるflatMap(g) ∘ fどこliftA1 = liftアバウトof ? まあ.of Kのアイデンティティ同形から来ます:Kの各々のアイデンティティ同形1 Aのために、1からの対応する機能がなければなりませんA to M<A> (i.e. of: <A>(a: A) => M<A> ).

    どこof 由来する

    法律
    最後の質問:法律はどこから来ますか?それらはtsに翻訳されたkのカテゴリー法だけです:

    ケイ
    TS
    左のアイデンティティ
    1 B∘ f' = f' flatMap(of) ∘ f = f正しいアイデンティティf' ∘ 1 A =f' flatMap(f) ∘ of = f結合性h' ∘ (g' ∘ f') = (h' ∘ g') ∘ f' flatMap(h) ∘ (flatMap(g) ∘ f) = flatMap((flatMap(h) ∘ g)) ∘ f
    モナドfp-tsインfp-ts the flatMap 関数は、chain , 基本的にはflatMap 引数を並べ替えて
    flatMap: <A, B>(f: (a: A) => HKT<M, B>) => ((ma: HKT<M, A>) => HKT<M, B>)
    chain:   <A, B>(ma: HKT<M, A>, f: (a: A) => HKT<M, B>) => HKT<M, B>
    
    注意chain から得られるflatMap (とviceversa ).
    入れ子になったコンテキストの問題を示す例に戻ると、chain
    import { array, head } from 'fp-ts/Array'
    import { Option, option } from 'fp-ts/Option'
    
    const followersOfFollowers: Array<User> = array.chain(getFollowers(user), getFollowers)
    
    const headInverse: Option<number> = option.chain(head([1, 2, 3]), inverse)
    

    結論
    機能的プログラミングは、効果を備えた機能を構成するための普遍的な方法を提供します.
    関数型プログラミングは本当に作文について