関数.関数JSを書くためのばかガイド(その2 )


iでは関数型プログラミングのコア概念を導入した.その記事では、我々はすぐに純粋な機能の上で手探りしました.この記事では、より詳細に機能を議論します.
関数プログラミングをするために絶対に必要と呼ぶことが一つあるならば、関数の良い理解です.(関数* alプログラミングから名前を推測することができました)

関数とは


あなたがどんな種類のプログラマーであれば、あなたは多分すでに機能に精通しています.しかし、私はまだどのような機能ですか?
私はいくつかのJSのフォークを聞いて、私は機能が何か知っている.
function doSomething(x) {
  return x + 42;
}
これが👆) 事.または
const addTwo = function (x) {
  return x + 2;
}
または実際の賢い男の思考、この

const addOne = x => x + 1
はい、これらはすべて機能です.
しかし、それらは関数の例です.私があなたに考えて欲しいことは、

What is a function? What does it do?


ご存知のように、コンピューターサイエンスの世界は数学の世界と非常に絡み合っています.関数は、我々が数学の世界から借りる多くのものの1つです.
しかし、数学は非常に抽象的です.そして、あなたが数学の機能の定義を探すなら、あなたは複数を見つけるでしょう.私が好きなのは

A function is a relation between 2 sets


または抽象的ではなく、コンピュータサイエンスのy項

A function is a mapping between an input and an output


したがって、関数はいくつかの入力を受け取り、いくつかの出力を返すものです.
現在では、関数が関数と見なされる前に、以下の規則が必要とされています.
  • 複数の入力を1つの出力にマップすることができます
  •   // for a function fx,
      fx(1) // => true
      fx(-1) // => true
    
  • 同じ入力は、複数の出力にマップすることはできません.
  • これは、非決定性の行動につながるので、これはコンピュータサイエンスと数学の両方で望ましくない.
      fx(1) // it should not be true once and false the next second.
    
    今、あなたは考えているかもしれません.

    What about functions that don't return anything.


    私は、他の言語でこれの動作について知りません(また、この議論の目的を気にかけません)、しかし、JSでは、あなたの機能は常にあなたが望むかどうか何かを返します.
    あなたが何かを返すならば、それはよくて良いです.
    しかし、あなたがそうしないならば、JSは帰りますundefined あなたに.
    したがって、何も返さない関数は、実際にはundefined . しかしもっと重要なことに、あなたは他の場所でそのような関数の結果を得ているかもしれません.多分、関数はその結果をスコープ外の変数にプッシュしているかもしれません.
    その場合、その不純な機能とその原因副作用.そして、あなたはおそらくそれを行うことを避けるべきです.
    しかし、あなたは考えているかもしれません.

    What about functions that don't take an input.


    これは、いくつかの方法のいずれかに行くことができます.
  • あなたの関数は、何も入力しないでそれを呼び出す場合は常に貴重な値を返します.
    あなたの関数は、NULL集合(何も)から値
    関数.

  • あなたの関数は何も入力せず、undefined ) 我々が議論したように.
  • 役に立たない(何もしない)、しかし、その機能.
  • その有用な(すなわち出力を与えます)、しかし、その出力は戻り値として利用できません、そして、その(純粋な)機能でない、そして、あなたは副作用を作ることとしてこれらを避けるべきです!
  • だから、我々は今どのような機能は、それが正しいか知っている?それはすべての機能について知っていることですか?
    いいえ、私の親愛なる読者.あなたはトンネルには、関数について学ぶ自分で掘ることができます.しかし、JSでFPを学習する私たちの目的のために.上記の規則に従ういくつかの特殊な機能について話をし、おもしろいことをすることができます.

    再帰関数


    どのような素因数がわかりますか?
    あなたのような数の後に感嘆符で数学で表現するこのもの5! .
    どうしたの?数学の興味深いビットは、我々は今議論するつもりはない多くのことに便利です.重要なのは、コードの階乗を取得した後に、数を後にして感嘆符を使うだけではないということです.我々は、その機能を自分で作る必要があります.
    幸いにも、素因数分解は非常に直感的です.因数分解についての2つのルールがあり、それらを任意の数の階乗を得ることができます.
  • 0の階乗は1です.
    または0! = 1
  • 数xの階乗はxをx - 1の階乗で乗算する.
  • またはn! = n ✕ (n-1)!例:5! = 5 * 4!ですから、3の階乗を見つけたかったら、こんなことになるでしょう.
    3! = 3 * 2!
    2! = 2 * 1!
    1! = 1 * 0!
    0! = 1
    
    Simplifying,
    3! = 3 * 2 * 1 * 1
    
    この振る舞いを関数で実装したいならfac . どうやってそんなことするの?
    あなたはおそらくループを考えています、そして、他のステートメントならば.しかし、我々は単語のための要因語の規則を取ることができる非常に簡単な方法があり、コードにそれを翻訳し、それが動作します.
    如し
    function fac (n) {
      if (n === 0) return 1 // this is our rule number 1 being satisfied.
      return n * fac(n-1) // rule number 2 being satisfied
    }
    
    それはthats!これは、階乗の非常にシンプルで機能的な実装です.
    では、どうやって動くの?
    これは再帰の例です何かをするか、結果を得るために自分自身を呼び出す関数.
    世界のすべての(意図的な)再帰では、少なくとも2つの論理的なケースが常にあります.
  • 関数が自分自身を呼び出していない場合(再帰は無限にはずれていません).
  • 関数が自身を呼び出す再帰的な場合.
  • 上の例では
    2行目はベースケースです.あなたが気づいたかもしれないように、これは通常簡単に計算できるか知られている何かです.
    線は、3は我々の再帰的なケースです.
    警告の言葉

    While JavaScript is usually a good enough language for exploring functional concepts, this is one of the places where functional and JS doesn't necessarily agree.

    A recursion is usually fine for simple algorithms that don't need too many recursive calls in JS. But, if your algorithms does a recursive call way too many times, its either not gonna perform well or going to crash because of a stack overflow.

    In future, We might discuss techniques such as memoization to get over this kind of limitations or to make our code more performant than a naive recursion.


    高次関数


    前に議論したように、ポイントをまっすぐにしましょう.関数は入力から出力へのマッピングです.
    高次関数はマップする関数です.
  • 関数( s )から出力まで
  • 入力から関数へ
  • 関数( input )から関数( output )へ
  • そのすべてを吸収する瞬間をください.関数がこれらの3つのもののいずれかを行う場合、その上位関数.
    いくつかの例を見てください.
    function propSatisfies(prop, pred, obj) {
      let val = obj[prop]
      return pred(val)
    }
    
    let data = {
      age: 21
    }
    
    function isAdult (age) {
      return age >= 18
    }
    
    propSatisfies('age', isAdult, data) //=> true
    
    上の例では
    機能propSatisfies 3つのパラメータを入力します.prop : 文字列(プロパティ名)pred : 入力を受け取り、trueまたはfalseを返す関数obj : その物体prop プロパティはpred .
    この関数は、true or false最後の行ではpropSatisfies 関数を使用して3値prop => 'age' pred => isAdult obj => data isAdult 年齢と収益を取る単純な関数ですtrue or false (述語).これは高次関数ではない'age' は文字列リテラルで、高次関数obj オブジェクトは高次関数ではなくオブジェクトです.
    したがって、どちらが高次関数か?propSatisfiesなぜ?関数をマップするためです(isAdult ) 値にtrue or false .
    別の高次の関数を見てみましょう.
    function add(a) {
      return function (b) {
        return a + b;
      }
    }
    
    let addOne = add(1) //=> this returns a function
    let addTen = add(10) //=> this too returns a function
    
    addTen(1) //=> returns 11
    
    この例ではadd は1パラメータをとる関数です.a (数)
    この関数は別の関数を返します.add , ここでは、関数を返すので、高次関数です.
    我々add 機能も閉鎖と呼ばれる別の興味深いFPの概念を採用し、我々はどのように機能とクロージャは別の日に動作する方法について説明します.この議論の目的のためにadd は別の関数を返すため、上位関数です.
    これらの両方を行う関数を見てみましょう.
    function combine(outer, inner) {
      return function (arg) {
        return outer(inner(arg))
      }
    }
    
    function double (num) {
      return 2 * num
    }
    
    function square (num) {
      return num * num
    }
    
    let dSquare = combine(square, double) //=> a function that doubles and then squares a number
    
    この例ではcombine 二つの引数をとるouter and inner , どちらも関数でなければなりません.したがって、我々はすでにそれが高次関数であることを見ることができますcombine また、内側と外側の両方の機能を組み合わせます.もう一度、その高次の関数(関数を返すため)
    我々がコンビと呼ぶときsquare and double 引数として、引数をとる関数を返しますarg を呼び出して値を返すinner with arg それから呼び出しouter 返り値inner コール.本質的には、2つの機能を組み合わせる.それでdSquare 現在の関数は、ときに番号を与えたときに、最初にそれを二倍にし、正方形をし、それらの操作の結果を返します.
    後の記事では、基本的にはcombine しかし、はるかに柔軟で強力です.(本当に好奇心の強い人たちのためにcompose ).

    それは今日のすべての人々です。


    平和✌️