国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Home php教程 PHP源碼 How to read and write cool functional code

How to read and write cool functional code

Nov 12, 2016 am 10:17 AM

Today I saw someone sharing the following functional code on Weibo. I posted the code below, but I slightly changed the original code. For the functional version, at first glance, it is indeed very impressive. It’s hard to explain. If you take a closer look, you might faint. It seems to be a complete book from heaven. It looks very pretentious, haha. However, I feel that parsing that functional code may be a more interesting process. Moreover, I have written an introductory article on "Functional Programming" before, and I can use this example to sublimate the original article. By the way, this article can better introduce a lot of basic knowledge to you, so I wrote this article.

How to read and write cool functional code

Let’s look at the code first

This code is unremarkable. It is an O(n) algorithm to find a number from an array. If it cannot find it, it returns null.

The following is the normal old-school way. Needless to say.

//正常的版本
function find (x, y) {
  for ( let i = 0; i < x.length; i++ ) {
    if ( x[i] == y ) return i;
  }
  return null;
}
let arr = [0,1,2,3,4,5]
console.log(find(arr, 2))
console.log(find(arr, 8))

The result is that the functional expression looks like this (it seems that the above codes are faintly visible below, but it is a little different. In order to eliminate the if language and make it look more like an expression, use ? expression):

//函數(shù)式的版本
const find = ( f => f(f) ) ( f =>
  (next => (x, y, i = 0) =>
    ( i >= x.length) ?  null :
      ( x[i] == y ) ? i :
        next(x, y, i+1))((...args) =>
          (f(f))(...args)))
let arr = [0,1,2,3,4,5]
console.log(find(arr, 2))
console.log(find(arr, 8))

In order to explain this code clearly, you need to add some knowledge first.
Javascript’s arrow function



First of all, let’s briefly explain the arrow expression introduced by ECMAScript2015. Arrow functions are actually anonymous functions, and their basic syntax is as follows:

(param1, param2, …, paramN) => { statements } 
(param1, param2, …, paramN) => expression
     // 等于 :  => { return expression; } 
// 只有一個參數(shù)時,括號才可以不加:
(singleParam) => { statements }
singleParam => { statements }
//如果沒有參數(shù),就一定要加括號:
() => { statements }

Here are some examples:

var simple = a => a > 15 ? 15 : a; 
simple(16); // 15
simple(10); // 10
let max = (a, b) => a > b ? a : b;
// Easy array filtering, mapping, ...
var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b);  // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2);       // [10, 12, 26, 0, 2, 36, 46]

It doesn’t look complicated. However, the first two simple and max examples above both assign the arrow function to a variable, so it has a name. Sometimes, certain functions are called when they are declared, especially in functional programming, when a function also returns an external function. For example, in this example:

function MakePowerFn(power) {
  return function PowerFn(base) {
    return Math.pow(base, power);
  } 
}
power3 = MakePowerFn(3); //制造一個X的3次方的函數(shù)
power2 = MakePowerFn(2); //制造一個X的2次方的函數(shù)
console.log(power3(10)); //10的3次方 = 1000
console.log(power2(10)); //10的2次方 = 100

In fact, the PowerFn in the MakePowerFn function does not need to be named at all. It can be written as:

function MakePowerFn(power) {
  return function(base) {
    return Math.pow(base, power);
  } 
}

If you use arrow functions, it can be written as:

MakePowerFn = power  => {
  return base => {
    return Math.pow(base, power);
  } 
}

We can also write More concise (if you use expressions, you don't need { and }, and return statements):

MakePowerFn = power => base => Math.pow(base, power)

I still add parentheses, and Line breaks may make it clearer:

MakePowerFn = (power) => (
  (base) => (Math.pow(base, power))
)

Okay, with the above knowledge, we can enter a more advanced topic - recursion of anonymous functions.
Recursion of anonymous functions


Functional programming aims to eliminate stateful functions and for/while loops with function expressions. Therefore, for/while loops should not be used in the world of functional programming. , instead use recursion (the performance of recursion is very poor, so tail recursion is generally used for optimization, that is, the calculation status of the function is passed down layer by layer as parameters, so that the language compiler or The interpreter does not need to use the function stack to help you save the state of the internal variables of the function).

Okay, so, how to do recursion of anonymous functions?

Generally speaking, recursive code means that the function calls itself. For example, our code for finding factorial:

function fact(n){
  return n==0 ? 1 :  n * fact(n-1);
};
result = fact(5);

How to write this recursion under an anonymous function? For anonymous functions, we can pass the anonymous function as a parameter to another function. Because the parameters of the function have names, we can call ourselves. As shown below:

function combinator(func) {
  func(func);
}

Is this a bit suspicious of cheating? Anyway, let’s go further and transform the above function into an arrow function-style anonymous function.

(func) => (func(func))


Now you don’t seem like cheating. Inserting the factorial function above looks like this:

First, reconstruct the fact and remove the name that you call yourself in the fact:

function fact(func, n) {
  return n==0 ? 1 :  n * func(func, n-1);
}
fact(fact, 5); //輸出120

Then, we turn the above version into an arrow function Anonymous function version: var fact = (func, n) => ( n==0 ? 1 : n * func(func, n-1) )

fact(fact, 5)

Here, we still need to use a fact to save this Anonymous function, let's continue, we want the anonymous function to call itself when it is declared.

In other words, we need to treat the function

(func, n) => ( n==0 ? 1 :  n * func(func, n-1) )

as a calling parameter and pass it to the following function:

(func, x) => func(func, x)


Finally we get the following code:

( (func, x) => func(func, x) ) (  //函數(shù)體
  (func, n) => ( n==0 ? 1 :  n * func(func, n-1) ), //第一個調(diào)用參數(shù)
  5 //第二調(diào)用參數(shù)
);

It seems a bit convoluted, anyway, you Do you understand? It's okay, let's continue.
Use the recursion of higher-order functions


But the above recursive anonymous function calls itself, so there are actual parameters of hard code in the code. We want to remove the actual parameters, how to remove them? We can refer to the MakePowerFn example mentioned earlier, but this time it is a recursive version of a higher-order function.

HighOrderFact = function(func){
  return function(n){
    return n==0 ? 1 : n * func(func)(n-1);
  };
};

We can see that the above code simply requires a function as a parameter and then returns the recursive version of this function. So, how do we call it?

fact = HighOrderFact(HighOrderFact);
fact(5);

連起來寫就是:

HighOrderFact ( HighOrderFact ) ( 5 )

但是,這樣讓用戶來調(diào)用很不爽,所以,以我們一個函數(shù)把 HighOrderFact ( HighOrderFact ) 給代理一下:

fact = function ( hifunc ) {
  return hifunc ( hifunc );
} (
  //調(diào)用參數(shù)是一個函數(shù)
  function (func) { 
    return function(n){
      return n==0 ? 1 : n * func(func)(n-1);
    };
  }
);
fact(5); //于是我們就可以直接使用了

用箭頭函數(shù)重構(gòu)一下,是不是簡潔了一些?

fact = (highfunc => highfunc ( highfunc ) ) (
  func => n =>  n==0 ? 1 : n * func(func)(n-1)
);

上面就是我們最終版的階乘的函數(shù)式代碼。
回顧之前的程序

我們再來看那個查找數(shù)組的正常程序:

//正常的版本
function find (x, y) {
  for ( let i = 0; i < x.length; i++ ) {
    if ( x[i] == y ) return i;
  }
  return null;
}

先把for干掉,搞成遞歸版本:

function find (x, y, i=0) {
  if ( i >= x.length ) return null;
  if ( x[i] == y ) return i;
  return find(x, y, i+1);
}

然后,寫出帶實參的匿名函數(shù)的版本(注:其中的if代碼被重構(gòu)成了 ?號表達式):

( (func, x, y, i) => func(func, x, y, i) ) (  //函數(shù)體
  (func, x, y, i=0) => (
      i >= x.length ?  null :
         x[i] == y  ?  i : func (func, x, y, i+1)
  ), //第一個調(diào)用參數(shù)
  arr, //第二調(diào)用參數(shù)
  2 //第三調(diào)用參數(shù)
)

最后,引入高階函數(shù),去除實參:

const find = ( highfunc => highfunc( highfunc ) ) (
   func => (x, y, i = 0) => (
     i >= x.length ?  null :
           x[i] == y  ?  i : func (func) (x, y, i+1)
   )
);

注:函數(shù)式編程裝逼時一定要用const字符,這表示我寫的函數(shù)里的狀態(tài)是 immutable 的,天生驕傲!

再注:我寫的這個比原來版的那個簡單了很多,原來版本的那個又在函數(shù)中套了一套 next, 而且還動用了不定參數(shù),當(dāng)然,如果你想裝逼裝到天上的,理論上來說,你可以套N層,呵呵。

現(xiàn)在,你可以體會到,如此逼裝的是怎么來的了吧?。
其它

你還別說這就是裝逼,簡單來說,我們可以使用數(shù)學(xué)的方式來完成對復(fù)雜問題的描述,那怕是遞歸。其實,這并不是新鮮的東西,這是Alonzo Church 和 Haskell Curry 上世紀(jì)30年代提出來的東西,這個就是 Y Combinator 的玩法,關(guān)于這個東西,你可以看看下面兩篇文章:《The Y Combinator (Slight Return)》,《Wikipedia: Fixed-point combinator》

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undress AI Tool

Undress AI Tool

Undress images for free

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)