JavaScript 를 이용 하여 Y 조합 자 를 유도 합 니 다.
Y 조합 자 는 lambda 연산 의 일부분 으로 존 치 이론 적 인 것 에 속한다.
lambda 연산 은 이름 을 정의 할 수 없 지만 재 귀 는 이름 을 통 해 함수 자 체 를 호출 해 야 합 니 다.그렇다면 어떻게 익명 재 귀 함 수 를 구축 합 니까?이것 이 바로 Y 조 합자 가 해결 해 야 할 문제 다.
간단 한 예 를 들 어 일반적인 재 귀 함수:
// n+(n-1)+(n-2)+...+1+0
var sum = (n) => {
if (n===0) {
return 0
} else {
// “sum” ,
return n+sum(n-1)
}
}
어떤 신기 한 힘 (Y 조합 자) 이 있 습 니까? 재 귀 함 수 를 아래 의 형식 으로 바 꿉 니 다.
// Y Y ,sumR sum recursion
var sum = Y((sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
//
// sumR sum recursion
return n+sumR(n-1)
}
}
})
자신 을 인용 하지 않 고 재 귀 를 이 루 고 있 습 니 다.
이것 이 바로 오늘 우리 가 해 야 할 일이 다.이 신기 한 힘 을 찾 아 라.
유도 과정
유도 과정 은 이해 하기 어렵 기 때문에 이 과정 을 두 부분 으로 나 누 었 다.
첫 번 째 부분 에서 하나의 일반 함수 에 대해 일련의 변 화 를 하여 재 귀 를 실현 할 수 있 는 함 수 를 도 출 한다.
두 번 째 부분 에서 이 재 귀 함수 에 대해 등가 의 전환 을 하고 이 재 귀 함수 에서 Y 조합 자 를 추출 합 니 다.
제1 부분
함수 에서 자신 을 인용 할 수 없 기 때문에, 우 리 는 먼저 몇 개의 함 수 를 정의 합 니 다.
// eternity , 。 。
// console.error , 。。
var eternity = () => {
// while(true) {}
console.error('you are in eternity')
}
// sum0 , 0 , , 。。
var sum0 = (n) => {
if (n===0) {
return 0
} else {
return n+eternity()
}
}
// sum1 , 0, 1
var sum1 = (n) => {
if (n===0) {
return 0
} else {
return n+sum0(n-1)
}
}
// sum2 , 0, 1, 2
var sum2 = (n) => {
if (n===0) {
return 0
} else {
return n+sum1(n-1)
}
}
만약 이렇게 계속 정의 할 수 있다 면, 우 리 는 충분 한 n 을 처리 할 수 있 는 함 수 를 정의 할 수 있 을 것 이다.
위의 sum 0, sum 1, sum 2 를 살 펴 보면 비슷 한 점 이 많 고 자 연 스 럽 게 mkSum 을 정의 하여 생 성 해 야 한다 고 생각 합 니 다.
// sumN
var mkSum = (fn) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+fn(n-1)
}
}
}
var sum0 = mkSum(eternity)
var sum1 = mkSum(sum0)
var sum2 = mkSum(sum1)
이렇게 하면 눈 에 띄 는 게 많아 요. 그 렇 죠?
다음 중요 한 곳 이 오 겠 습 니 다. 집 중력 에 주의 하 세 요.
eternity 함 수 는 영원히 실행 할 수 없 기 때문에, 그렇다면, 나 는 왜 다른 함수 로 바 꾸 지 않 습 니까?어떤 함수 로 바 꿔 도 똑 같 습 니 다. 그럼 제 가...
eternity 를 mksum 으로 바 꿔 주세요.
var sum0 = mkSum(mkSum)
var sum1 = mkSum(sum0)
var sum2 = mkSum(sum1)
관찰 하기 편리 하도록 sum 1, sum 2 를 펼 쳐 다음 과 같이 얻 을 수 있 습 니 다.
var sum0 = mkSum(mkSum)
var sum1 = mkSum(mkSum(mkSum))
var sum2 = mkSum(mkSum(mkSum(mkSum)))
위의 세 함수 정 의 를 자세히 보 세 요. 무엇 을 알 아 냈 습 니까?
맞다!이 세 가지 함 수 는 모두 mkSum 이 조합 하여 만 든 것 입 니 다!!Σ(っ °Д °;)っ
자세히 살 펴 보면 sum 이 처리 할 n 이 n + 1 로 변 할 때마다 가장 안쪽 에 있 는 mkSum 을 mkSum (mkSum) 으로 바 꾸 면 됩 니 다.
sum 0 의 맨 안쪽 mkSum 을 mkSum (mkSum) 으로 바 꾸 면 sum 1 입 니 다.같은 이치 로 sum 1 의 맨 안쪽 mkSum 을 mkSum (mkSum) 으로 바 꾸 면 sum 2 가 됩 니 다.
어 때? 돌아 오 는 냄새 좀 맡 았 지?가장 중요 한 것 은 필요 할 때 mkSum 을 mkSum (mkSum) 으로 어떻게 바 꾸 느 냐 하 는 것 이다.
만약 이 점 을 할 수 있다 면 우 리 는 재 귀 를 실현 할 수 있 을 것 이다.(ΦωΦ)
다음은 sum 0 을 보 여 드 리 겠 습 니 다. sum 0 에서 mkSum 에 게 전 달 된 매개 변 수 는 그 자체 이기 때 문 입 니 다. mkSum 의 매개 변수 이름 을 바 꿔 보 겠 습 니 다. mkSum 을 구별 하기 위해 mkSum 1 로 바 꾸 겠 습 니 다.
// mkSum1 mkSum
var mkSum = (mkSum1) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+mkSum1(n-1)
}
}
}
var sum0 = mkSum(mkSum)
앞서 언급 했 듯 이 사상 을 유도 하 는 관건 은 필요 할 때 mkSum 을 mkSum (mkSum) 으로 바 꾸 는 것 이다.
그럼 언제 가 필요 할 까요? 그렇습니다. 바로 귀속 함수 가 자신 을 호출 하려 고 할 때 입 니 다!
그래서 우 리 는 mkSum 을 아래 의 모습 으로 개조 했다.
// 。 。( ̄ω ̄)
var mkSum = (mkSum1) => {
return (n) => {
if (n===0) {
return 0
} else {
// ! !! mkSum mkSum(mkSum)
return n+mkSum1(mkSum1)(n-1)
}
}
}
// , sum0 sum
var sum = mkSum(mkSum)
여기 가 바로 유도 과정 에서 가장 관건 적 이 고 이해 하기 어 려 운 부분 입 니 다. 이 단계 에 이 르 러 재 귀 효 과 를 실 현 했 고 sum 은 완벽 하 게 운행 할 수 있 습 니 다.
다음은 mkSum 함수 에 대해 등가 전환 을 하여 진정한 Y 조합 자 를 추상 화 하 는 것 입 니 다. 그러나 위의 부분 을 알 아야 아래 의 내용 을 계속 볼 수 있 습 니 다.
제2 부분
진정한 Y 조합 을 추상 화하 다
작은 방법
아래 의 추론 에 앞서 여러분 이 아래 의 내용 을 잘 이해 할 수 있 도록 작은 방법 을 쓰 고 아래 의 추론 에서 많은 부분 을 사 용 했 습 니 다.
그것 은 함수 중의 일부 내용 을 어떻게 추출 하여 매개 변수 로 하 는 것 입 니까?
var d = 1, e = 2
//
var a = c => {
var b = d + e
return b + c
}
// , b ,
var aCreator = b => c => b+c
var a = aCteator(d+e)
a(10)
다음 내용 에서 특정한 것 을 추출 하여 매개 변수 형식 으로 바 꾸 는 것 과 관련 된 표현 은 모두 이런 방법 을 이용 한 것 이다.
우선, 우 리 는 mkSum 함수 의 형식 을 간단하게 바 꾸 고 mkSum 1 (mkSum 1) 을 추출 하여 매개 변수 형식 으로 바 꿉 니 다.
var mkSum = (mkSum1) => {
var sumR = mkSum1(mkSum1)
// sumFn Y ?!
var sumFn = (sumR) => {
(n) => {
if (n===0) {
return 0
} else {
// mkSum1(mkSum1) , sumR
return n+sumR(n-1)
}
}
}
return sumFn(sumR)
}
var sum = mkSum(mkSum)
간단 한 추출 입 니 다. 이 함수 로 sum (3) 을 실행 해 보 시 겠 습 니까?
어 머?? 아까 는 멀쩡 했 는데 왜 갑자기 창고 가 터 졌어?Д°)
구체 적 인 원인 은 설명 하지 않 고 잘 생각해 보면 답 이 나온다.
스 택 폭발 문 제 를 해결 하기 위해 mk Sum 1 (mk Sum 1) 밖 에 함 수 를 한 층 싸 면 됩 니 다.
var mkSum = (mkSum1) => {
// ,
var sumR = (x) => mkSum1(mkSum1)(x)
var sumFn = (sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
}
return sumFn(sumR)
}
var sum = mkSum(mkSum)
다음은 sum 의 mkSum 추출 을 매개 변수 형식 으로 바 꿉 니 다.
var mkSum = (mkSum1) => {
var sumR = (x) => mkSum1(mkSum1)(x)
var sumFn = (sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
}
return sumFn(sumR)
}
var w = f => f(f)
// mkSum(mkSum) w
var sum = w(mkSum)
우 리 는 다시 sumfn 을 mkSum 밖으로 추출 하여 매개 변수 형식 으로 바 꿉 니 다.
// sumFn
var sumFn = (sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
}
var mkSumCreator = (sumFn) => (mkSum1) => {
var sumR = (x) => mkSum1(mkSum1)(x)
return sumFn(sumR) // sumFn
}
var mkSum = mkSumCreator(sumFn)
var w = f => f(f)
var sum = w(mkSum)
다시 빵 한 층 함수 로 Y 조합 자의 원형 으로
var sumFn = (sumR) => {
return (n) => {
if (n === 0) {
return 0
} else {
return n + sumR(n - 1)
}
}
}
// , Y
var poorY = () => {
var mkSumCreator = (sumFn) => (mkSum1) => {
var sumR = (x) => mkSum1(mkSum1)(x)
return sumFn(sumR)
}
var mkSum = mkSumCreator(sumFn)
var w = f => f(f)
return w(mkSum)
}
var sum = poorY()
마지막 으로 최종 효 과 를 살 펴 보 자.
var sumFn = (sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
}
var sum = Y(sumFn)
어떻게 하면 이런 식 으로 변 할 수 있 을 까? 이 단 계 는 분명 하지 않 기 때문에 자세히 살 펴 봐 야 할 것 같다.
우 리 는 poory 에 인자 sumfn 을 추가 하고 가장 외부 sumfn 을 매개 변수 로 전달 하면 됩 니 다.
var sumFn = (sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
}
// poorY sumFn
var poorY = (sumFn) => {
// poorY
var mkSumCreator = (sumFn) => (mkSum1) => {
var sumR = (x) => mkSum1(mkSum1)(x)
return sumFn(sumR)
}
var mkSum = mkSumCreator(sumFn)
var w = f => f(f)
return w(mkSum)
}
// sumFn poorY,
var sum = poorY(sumFn)
이때, 수많은 Y 그룹 이 드디어 나 옵 니 다. 보이 시 나 요?!
poory 내부 의 mkSumCreator 가 직접 호출 되 었 기 때문에 이 를 간소화 할 수 있 습 니 다. 그러면 우 리 는 진정한 Y 조합 을 얻 을 수 있 습 니 다.
var sumFn = (sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
}
var y = (sumFn) => {
//
var mkSum = (mkSum1) => {
var sumR = (x) => mkSum1(mkSum1)(x)
return sumFn(sumR)
}
var w = f => f(f)
return w(mkSum)
}
var sum = y(sumFn)
마지막 으로 우 리 는 남 은 이름 을 지우 고 Y 조합 자 를 추출 합 니 다.
var Y = (sumFn) => {
var w = f => f(f)
return w(mkSum1 => {
var sumR = (x) => mkSum1(mkSum1)(x)
return sumFn(sumR)
})
}
var sum = Y((sumR) => {
return (n) => {
if (n===0) {
return 0
} else {
return n+sumR(n-1)
}
}
})
간소화 Y 조합 자:
//
// w -> (f => f(f))
// mkSum1 -> b
// sumFn -> fn
var Y = fn =>
(f => f(f))
(b => fn( x => b(b)(x) ))
앞서 mkSum 과 mkSum 1 은 엄 격 히 구별 할 필요 가 없다 고 말 했 습 니 다. 그 러 니 더 (그러므로) 간 (신) 화 (비) 를 위해 서 는 모두 f 로 교체 합 시다.
최종 Y 그룹:
var Y = fn =>
(f => f(f))
(f => fn( x => f(f)(x) ))
// f => f(f)
var Y = fn =>
(f => fn( x => f(f)(x) ))
(f => fn( x => f(f)(x) ))
세심 한 친 구 는 이 Y 조합 자가 생 성 한 재 귀 함수 가 하나의 매개 변수, 즉 Y 그룹 합 자 안의 x 만 처리 할 수 있다 는 것 을 알 아야 합 니 다. 따라서 우 리 는 Y 조합 자가 생 성 한 재 귀 함수 가 매개 변수 에 제한 을 받 지 않도록 수정 할 수 있 습 니 다.
var Y = fn =>
(f => f(f))
(f => fn( (...x) => f(f)(...x) ))
엔 딩
추론 은 여기 서 끝 이 야. 알 겠 어? 없 으 면...
다음 글 을 참고 할 수 있 습 니 다.https://zhuanlan.zhihu.com/p/20616683 (이 글 은 더욱 투철 하 게 말한다).
또는 의 9 장 을 읽 어 보 세 요.
마지막 으로 지적 하고 자 하 는 것 은 실제 응용 에서 재 귀적 실현 은 Y 조합 자 에 의 해 이 루어 지 는 것 이 아니 라 함수 의 인용 (예 를 들 어 지침) 을 먼저 저장 한 다음 에 필요 할 때 지침 을 통 해 자신의 함 수 를 호출 하 는 것 이다. 이것 은 우리 의 직관 과 부합된다.
그래서 Y 조 합 자 를 이해 하 는 것 은 아무 소 용이 없다. 그저 심심 해서 학 대 를 찾 을 뿐이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.