xxleyi / learning_list

聚集自己的学习笔记
10 stars 3 forks source link

函数式编程:历史节点和核心概念简介 #60

Open xxleyi opened 5 years ago

xxleyi commented 5 years ago

大纲:


作为一种编程风格的函数式编程

functional programming:

imperative programming:

xxleyi commented 5 years ago

some relative concepts:


为什么Lisp语言如此先进?(译文) - 阮一峰的网络日志

Lisp和Fortran代表了编程语言发展的两大方向。前者的基础是数学,后者的基础是硬件架构。 从那时起,这两大方向一直在互相靠拢。Lisp刚设计出来的时候,就很强大,接下来的二十年,它提高了自己的运行速度。而那些所谓的主流语言,把更快的运行速度作为设计的出发点,然后再用超过四十年的时间,一步步变得更强大。

Lisp语言诞生的时候,就包含了9种新思想。其中一些我们今天已经习以为常,另一些则刚刚在其他高级语言中出现,至今还有2种是Lisp独有的。按照被大众接受的程度,这9种思想依次是:

  1. 条件结构(即"if-then-else"结构)。现在大家都觉得这是理所当然的,但是Fortran I就没有这个结构,它只有基于底层机器指令的goto结构。

  2. 函数也是一种数据类型。 在Lisp语言中,函数与整数或字符串一样,也属于数据类型的一种。它有自己的字面表示形式(literal representation),能够储存在变量中,也能当作参数传递。一种数据类型应该有的功能,它都有。

  3. 递归。 Lisp是第一种支持递归函数的高级语言。

  4. 变量的动态类型。 在Lisp语言中,所有变量实际上都是指针,所指向的值有类型之分,而变量本身没有。复制变量就相当于复制指针,而不是复制它们指向的数据。

  5. 垃圾回收机制。

  6. 程序由 表达式(expression) 组成。Lisp程序是一些表达式区块的集合,每个表达式都返回一个值。这与Fortran和大多数后来的语言都截然不同,它们的程序由 表达式和语句(statement) 组成。

more ......

函数是图灵完备的,全能的。但函数式编程绝对不是全部。

xxleyi commented 5 years ago

image image image image image image image

xxleyi commented 5 years ago

我们印象中的函数式编程:

xxleyi commented 5 years ago

函数式编程真正的核心:

与之对应的历史节点:

xxleyi commented 5 years ago

Lambda Calculus:布尔数和布尔逻辑的 lambda calculus 实现

const True = x => y => x
const False = x => y => y
const Not = b => b(False)(True)
const If = Condition => Then => Else => Condition(Then)(Else)
const isTrue = () => "it's true!"
const isFalse = () => "it's false!"
const First = If(True)(isTrue)(isFalse)
const Second = If(False)(isTrue)(isFalse)
First() // "it's true!"
Second() // "it's false!"
const And = Exp1 => Exp2 => Exp1(Exp2)(Exp1)
const Or = Exp1 => Exp2 => Exp1(Exp1)(Exp2)
const Result1 = If(And(True)(True))(isTrue)(isFalse)
const Result2 = If(And(True)(False))(isTrue)(isFalse)
const Result3 = If(Or(False)(True))(isTrue)(isFalse)
const Result4 = If(Or(False)(False))(isTrue)(isFalse)
Result1() // "it's true"
Result2() // "it's false"
Result3() // "it's true"
Result4() // "it's false"

Lambda Calculus:递归的 lambda calculus 实现

const Y = f => (x => x(x))(x => f(y => x(x)(y)))
const fact_gen = f => (n => ((n === 0) ? 1 : n * f(n - 1)))
const fact = Y(fact_gen);
[1, 2, 3, 4, 5].map(fact)
// [1, 2, 6, 24, 120]

It is worth mentioning that the codification in Lambda Calculus does not aim at a practical implementation of data types but rather a formal demonstration that these are not necessary to represent any calculation, since, using only functions, it is possible to simulate them.

FROM: Lambda Calculus with JavaScript – Alexandre Thebaldi – Medium Lambda Calculus: The Y combinator in javascript

xxleyi commented 5 years ago

Immutable (Persistent Data Structures)

方案一:Copies & Mutate: 🐢 😔

image

方案二:Tree & Sharing: 🚀 😄

image

xxleyi commented 5 years ago

Effects (handle side effects)

方式一:Redux saga

app.model({
  namespace: 'todo',
    state: [],
  reducers: {
    add(state, { payload: todo }) {
      // Save data to state
      return [...state, todo];
    },
  },
  effects: {
    *save({ payload: todo }, { put, call }) {
      // Call saveTodoToServer, then trigger `add` action to save data
      yield call(saveTodoToServer, todo);
      yield put({ type: 'add', payload: todo });
    },
  },
});

方式二:React hooks: useEffect

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

We intend for Hooks to cover all existing use cases for classes, but we will keep supporting class components for the foreseeable future.

Hooks API Reference:

import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { KEY_ESCAPE } from 'keycode-js';

import CloseIcon from 'icons/CloseIcon';

const ModalCloseButton = (props) => {
    const handleEscapeKeyDown = (e) => {
        if (e.keyCode === KEY_ESCAPE) {
            props.onRequestClose();
        }
    };

    useEffect(() => {
        window.addEventListener('keydown', handleEscapeKeyDown);

        return () => {
            window.removeEventListener('keydown', handleEscapeKeyDown);
        };
    }, []);

    return (
        <button aria-label="Close" onClick={props.onRequestClose}>
            <CloseIcon />
        </button>
    );
}

ModalCloseButton.propTypes = {
    onRequestClose: PropTypes.func.isRequired,
};

export default ModalCloseButton;

方式三:Elm 架构

These state management patterns and even Redux itself can be easily integrated into Vue applications. In fact, Vue has even taken this model a step further with Vuex, an Elm-inspired state management solution that integrates deeply into Vue that we think offers a superior development experience.

image

xxleyi commented 5 years ago

结论

前端程序员完全可以做到用描述性的思维逻辑,只写纯函数来完成携带各种状态管理的业务逻辑。

Vue

image

React

import ModalCloseButton from './modal-close-button.js'

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
<div>
  <h1>
    Hello, {formatName(user)}!
  </h1>
  <ModalCloseButton />
</div>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

React and Vue share many similarities. They both:

  • utilize a virtual DOM
  • provide reactive and composable view components
  • maintain focus in the core library, with concerns such as routing and global state management handled by companion libraries

You’ll run across articles describing React as a declarative approach to building UIs.

React made its “declarative approach” quite popular and upfront so it permeated the frontend world along with React.

It’s really not a new concept, but React took building UIs a lot more declaratively than with HTML templates:

  • you can build Web interfaces without even touching the DOM directly
  • you can have an event system without having to interact with the actual DOM Events

The opposite of declarative is imperative. A common example of an imperative approach is looking up elements in the DOM using jQuery or DOM events. You tell the browser exactly what to do, instead of telling it what you need.

The React declarative approach abstracts that for us. We just tell React we want a component to be rendered in a specific way, and we never have to interact with the DOM to reference it later.