함수 조합기만 사용하여 체인 테이블 만들기


오늘, 나는 Object 또는 Arrays 같은 데이터 구조를 사용하지 않고 체인 테이블을 만드는 방법을 보여 줄 것이다.반대로 함수 조합을 사용합니다.
나는 네가 체인 시계가 무엇인지 이미 익숙하다고 가정한다.링크 목록을 업데이트하려면
.
나의 목표는 네가 이전에 보지 못했을 수도 있는 것들을 너에게 보여주는 것이다.curry, 일부 응용 프로그램, 패키지 닫기, 함수 조합의 가능성을 보여주기 위해서.가장 중요한 것은 이 일을 할 때 약간의 즐거움을 가져야 한다는 것이다.
⚠️ 본문에runkit이 박혀 있다.이 페이지의 예시를 실행, 수정, 조정 및 재생해야 합니다.

함수 조합자는 무엇입니까?


Thinking Functionally: Combinators 정의

The word "combinator" is used to describe functions whose result depends only on their parameters. That means there is no dependency on the outside world, and in particular, no other functions or global value can be accessed at all.

In practice, this means that a combinator function is limited to combining its parameters in various ways.


이것은 많은 고려를 해야 하기 때문에 아마도 몇 가지 예가 도움이 될 것이다.
/* ☝️ These are combinators */
const I = a => a
const K = a => b => a
const V = a => b => c => c (a) (b)
const B = a => b => c => a (b (c))
//        -    -    -    ---------
//         \   |   /        |
//           arguments   ---
//                      /
//       only arguments are used

/* 👎 These are not */
const nope = a => a.map(double)
//                  --- ------
//                 /           \    
//                /    ⚠️ reaching outside of the func
//               /
//     ⚠️ can't use map either.
const add => a => b => a + b
//                       -
//                      /
// ⚠️ Uh oh, `+` is not part of 'arguments'
위의 코드를 요약해 보세요. 조합부호는 그 매개 변수만 사용할 수 있습니다.이것은 외부 함수, 방법, 연산자를 포함하지 않습니다!
걱정하지 마세요. 그래도 좀 곤혹스러워요. 괜찮아요.(⊙_☉)

폐건물


일반적인 체인 테이블은 다음과 같은 데이터 구조를 사용합니다.
class Node {
  constructor(data, next) {
    this.data = data
    this.next = next
  }
}

/* or */

const node = (data, next) => ({ data, next })

/* or */

const node = (data, next) => [ data, next ]
그러나 우리는 어떠한 데이터 구조도 사용하지 않을 것이다.우리는 함수 조합을 사용할 것이다.
combinator 풀의 심층에 들어가기 전에 node의 기본 함수부터 시작합니다.
function node (data, next) {
//             ----  ----
//           /            \
//       our data       the next node
}
현재 우리는 datanext을 대상으로 하지 않고 어떻게 node을 방문합니까?만약 네가 callbacks이라고 말한다면, 너는 옳다!
/////////////////////////////////////////////////////////////
// //
//📌 참고: 이러한 코드 블록을 수정하고 실행할 수 있습니다//
// //
/////////////////////////////////////////////////////////////
기능 노드(데이터, 다음, 콜백) {
리셋 (데이터, 다음)
}
//나는 bind를 사용하여 나의 데이터와 다음 값을 저장할 수 있다.
상수 머리.바인딩 (null,'데이터','null)
//리셋을 사용하여 head에서 값을 읽습니다.
머리((데이터, 다음) = >{
{data,next}로 돌아가기
})
나는 bind을 사용하여 실현하는 것을 정말 좋아하지 않는다.그래서 나는 node 함수를 사용할 것이다. 그러면 나는 일부 응용 프로그램을 사용하여 datanext을 응용할 수 있다.이것은 bind을 사용하는 것과 같은 효과가 있지만 더욱 좋은 문법이 있을 것이다.
상수 노드 = 데이터 = > 다음 = > 콜백 = > 콜백 (데이터) (다음)
// ---- ---- -------- ---- ----
// \ | / / /
//매개 변수가 변환됨 -------------
// /
//패킷을 닫아 데이터 및 다음을 사용할 수 있습니다.
//마지막 호출 시 리셋합니다.
//나는 bind를 사용하여 나의 데이터와 다음 값을 저장할 수 있다.
const head=노드("데이터")(null)
// ------ ----
// / /
//우리는 파라미터 데이터와null을 부분적으로 응용할 수 있다.
//리셋을 사용하여 head에서 값을 읽습니다.
머리(데이터=>다음=>{
{data,next}로 돌아가기
})
지금, 만약 당신이 자세히 관찰한다면, 당신은 이미 node과 위의 V의 조합부호가 같다는 것을 알아차렸을 것입니다!
그래서 현재 node은 다음과 같이 감소할 수 있다.
const node = V
다음 노드를 생성할 수 있습니다.
const evenOdd = node ('Even') ('Odd')
const leftRight = node ('Left') ('Right')
const yesNo = node ('Yes') ('No')
만약 우리가 일부 응용 프로그램이 무엇을 하고 있는지 보려면 다음과 같이 보일 것이다.
// first copy the node function
const evenOdd = data => next => callback => callback (data) (next)

// apply 'Even' to data.
const evenOdd =         next => callback => callback ('Even') (next)

// apply 'Odd' to next.
const evenOdd =                 callback => callback ('Even') ('Odd')

// We end up with this:
const evenOdd = callback => callback ('Even') ('Odd')
evenOdd은 현재 callback의 매개 변수를 받아들입니다.callback에는 다음과 같은 함수가 필요합니다.
const callback = a => b => { /* ??? */ }
우리는 이제 시합을 시작할 수 있다.이 runkit에서 play을 클릭하고 callback을 수정하여 'Left'으로 돌아갑니다.
상수 V=a=>b=>c=>c(a)(b)
상수 노드 = V
const leftRight=노드("Left")(Right")
//TODO: 코드를 "Left"로 되돌리도록 콜백 수정
상수 리셋 = a=>b=>{}
leftRight(콜백)//=> "Left"'Right'으로 돌아가기 위해 코드를 다시 수정합니다.
경탄했어현재 우리는 'Left' 함수 data'Right' 함수 next을 호출합니다.
const data = a => _ => a
const next = _ => b => b
우리의 새로운 기능으로 다시 운행하다.
상수 V=a=>b=>c=>c(a)(b)
상수 노드 = V
상수 데이터 = a=>\u=>a
상량next=>b=>b
const leftRight=노드("Left")(Right")
위로하다로그(leftRight(data)
위로하다로그(leftRight(next)data도 우리의 K Combinator과 같다는 것을 알아차렸습니까?
// 💥 BOOM!
const data = K
nextK Combinator과 거의 일치하지만 약간 다르다.nextb, dataa을 반환합니다.작은 기교가 하나 있다.
// 🧙‍♀️ MAGIC!
const next = K (I)
이 교묘한 기교는 전체 문장의 영감의 원천이다.나는 네가 지금 2초도 안 돼서 이 문제를 해결할 수 있다고 내기한다.

목록 링크


우리들은 배운 내용을 하나의 체인 시계로 번역합시다.
상수 I=a=>a
상수 K=a=>b=>a
상수 V=a=>b=>c=>c(a)(b)
상수 노드 = V
상수 데이터 = K
상수 next=K (I)
const Nil=Symbol('Nil')///는 테스트가 끝난 대상일 뿐입니다.
const first= 노드('1st')(Nil)
// ---
// /
//0은 끝을 나타냅니다.
상수 초 = 노드('2nd')(첫 번째)
// -----
// /
//첫 번째 노드를 다음 노드로 전송
constthird=노드('3rd')(초)
// -----_
// /
//두 번째 노드를 다음 노드로 전송
위로하다로그(세 번째(데이터)/=> "세 번째"
위로하다로그 (다음)/= > 두 번째
위로하다로그 (다음) (데이터)/= > 첫 번째

그 목록을 세어 보세요.


우리는 목록을 일일이 열거하고 계수를 되돌려주는 간단한 함수를 만들 수 있다.
상수 I=a=>a
상수 K=a=>b=>a
상수 V=a=>b=>c=>c(a)(b)
상수 노드 = V
상수 데이터 = K
상수 next=K (I)
상수 Nil = 기호('Nil')
상수 길이 = (목록, 값 = 0) = >
목록 === 0
? 가치
: 길이(목록(다음), 값 +1)
const first= 노드('1st')(Nil)
상수 초 = 노드('2nd')(첫 번째)
constthird=노드('3rd')(초)
위로하다대수(길이(1위)/>1
위로하다대수(초)/>2
위로하다대수(길이(3분의 1)/>3

목록 매핑


매핑은 Array과 유사합니다.
상수 I=a=>a
상수 K=a=>b=>a
상수 V=a=>b=>c=>c(a)(b)
상수 노드 = V
상수 데이터 = K
상수 next=K (I)
상수 Nil = 기호('Nil')
//이 실현을 걱정하지 마세요.
//이것은 단지 아래의 코드를 보여 주는 것일 뿐이다.
상수 매핑 =func=> 목록 =>
목록 === 0
? 목록
: 노드 (func (list (data)) (func) (list (next))
const first= 노드('1st')(Nil)
상수 초 = 노드('2nd')(첫 번째)
constthird=노드('3rd')(초)
const upper=x=>x.toUpperCase()
const THIRD=매핑(상)(세 번째)
위로하다로그(세 번째(데이터)/=> "세 번째"
위로하다로그 (다음)/= > 두 번째
위로하다로그 (다음) (데이터)/= > 첫 번째

필터


필터도 Array과 유사하다.
상수 I=a=>a
상수 K=a=>b=>a
상수 V=a=>b=>c=>c(a)(b)
상수 노드 = V
상수 데이터 = K
상수 next=K (I)
상수 Nil = 기호('Nil')
//이 실현을 걱정하지 마세요.
//이것은 단지 아래의 코드를 보여 주는 것일 뿐이다.
상수 필터 = 술어 = > 목록 = >
목록 = = = 0?목록
: 술어 (목록 (데이터)?노드 (목록 (데이터) (필터 (술어) (목록 (다음)
: 필터 (술어) (목록 (다음)
const first= 노드(1)(Nil)
상수 초 = 노드 (2) (첫 번째)
constthird=노드(3)(초)
상수 네 번째 = 노드 (4) (3)
상수 isEven=x=>x%2==0
const evens= 필터(isEven)(4)
위로하다로그(evens(data))/>4
위로하다로그(evens(next)(data)))/>2

그런데 함수 조합이 정말 유용합니까?


물론, 너는 이렇게 체인 시계를 만들어서는 안 된다.사실, 우선, 너는 체인 시계를 만들어서는 안 된다.한 마디로 하면 이것들은 모두 학술적이다.
놀랍게도 함수 조합기는 실제 용도가 있다!
이 가능하다, ~할 수 있다,...
const B = a => b => c => a (b (c))
이렇게 쓰지 않는 한
const compose = f => g => x => f (g (x))
이게 맞습니다!B Combinator이면 compose!궁금하면 B Combinatorpipe입니다.
또 다른 유용한 실용 함수는 Q Combinator이다.람다는 그들의 도서관에 always이 있다.간단한 함수 조합기를 사용하여 다시 만들 수도 있습니다.
const always = K

const awesome = always ('Awesome!')

awesome () //=> 'Awesome!'
awesome (123) //=> 'Awesome!'
awesome ('hello') //=> 'Awesome!'
always도 내가 자주 사용하는 흔한 함수이다.이렇게 쓸 수 있습니다 (아래).이것은 통제 부작용에 매우 좋다.
const tap = func => val => {
  func (val) // execute my side effect
  return val // return the original value
}
우리도 이렇게 tap을 쓸 수 있다.
const tap = S (K)
이것은 함수와 조합을 만들 수 있는 정말 유용한 것들입니다!

총결산

  • 우리는 어떠한 데이터 구조도 사용하지 않은 상황에서 체인 테이블을 만드는 방법을 배웠다.
  • 우리는 함수 조합자가 무엇인지, 그것들이 어떻게 유용한지 배웠다.
  • 우리는curry, 일부 응용 프로그램과 패키지를 사용하여 데이터를 저장하는 방법을 배웠다.
  • 네가 뭘 더 배웠는지 알려줘!
    runkit의 예시에 대한 당신의 견해를 말씀해 주세요.나는 그것들을 나의 게시물에 더 많이 포함시킬 것을 고려하고 있다.
    함수 조합에 대한 지식을 더 알고 싶으세요?댓글로 알려주세요!
    만약 함수식 자바스크립트를 좋아한다면, 여기나 트위터에서 나를 팔로우하세요!

    좋은 웹페이지 즐겨찾기