2014-12-02 2 views
2

a 배열 요소에 대한 연관 작업 f의 경우 다음과 같은 관계가 유지되어야합니다. a.reduce(f)a.reduceRight(f)과 같아야합니다.JavaScript에서 reduceRight의 네이티브 구현이 잘못되었습니다.

실제로 연관성과 교환 성 모두의 연산에 대해서는 사실입니다. 예를 들어 :

var a = [1,2,3,4,5,6,7,8,9,0]; 
 

 
alert(a.reduce(add) === a.reduceRight(add)); 
 

 
function add(a, b) { 
 
    return a + b; 
 
}
그러나 그것은 연관하지만 교환 법칙이 성립하지 않은 작업에 대한 진정한 보유하지 않습니다. 예를 들어 :

var a = [[1,2],[3,4],[5,6],[7,8],[9,0]]; 
 

 
alert(equals(a.reduce(concat), a.reduceRight(concat))); 
 

 
function concat(a, b) { 
 
    return a.concat(b); 
 
} 
 

 
function equals(a, b) { 
 
    var length = a.length; 
 
    if (b.length !== length) return false; 
 
    for (var i = 0; i < length; i++) 
 
     if (a[i] !== b[i]) return false; 
 
    return true; 
 
}

우리는 reduceRight에 대한 f의 인수를 뒤집어 야하는 것은 그들이 동등한 만들려면 :

var a = [[1,2],[3,4],[5,6],[7,8],[9,0]]; 
 

 
alert(equals(a.reduce(concat), a.reduceRight(concatRight))); 
 

 
function concat(a, b) { 
 
    return a.concat(b); 
 
} 
 

 
function concatRight(b, a) { 
 
    return a.concat(b); 
 
} 
 

 
function equals(a, b) { 
 
    var length = a.length; 
 
    if (b.length !== length) return false; 
 
    for (var i = 0; i < length; i++) 
 
     if (a[i] !== b[i]) return false; 
 
    return true; 
 
}

이 날 것을 믿을 수 있습니다의 기본 구현이 잘못되었습니다. 그것은 그것을 함수 f 번째 파라미터를 확인하는 것이 합리적 right 이후

var REDUCE_ERROR = "Reduce of empty array with no initial value"; 

Array.prototype.reduceRight = function (f, acc) { 
    var a = this, length = a.length; 

    if (arguments.length < 2) { 
     if (length !== 0) var right = a[--length]; 
     else throw new TypeError(REDUCE_ERROR); 
    } else var right = acc; 

    while (length !== 0) right = f(a[--length], right, length, a); 

    return right; 
}; 

이전 값 (우측 값)을 나타낸다 :

는 I는 다음과 같이 reduceRight 기능이 구현되어야한다고 판단 . 현재 값은 왼쪽 값을 나타냅니다. 따라서 현재 값을 함수의 첫 번째 매개 변수 인 f으로 만드는 것이 좋습니다. 이러한 방식으로, 비 - 교환 적 연상 작용에 대해서조차도, 앞서 언급 한 관계가 성립한다.

그래서, 내 질문은 :

  1. 는 않습니다되지는 참으로 내가 한 방식으로 구현 될 reduceRight에 대한 더 많은 이해가?
  2. 이유는 무엇입니까? reduceRight은 내가했던 것처럼 구현되지 않았습니까?
+0

이하지 않다고해서 [ 'foldr'와'foldl'] (http://en.wikipedia.org/wiki/Fold_ (higher-order_function))은 다른 방향에서 작동합니까? 그것이 둘 다 갖는 점이며, 비 교환 적 연산은 필연적으로 다른 결과를 반환합니다. – ssube

+0

@ssube 그들은 다른 방향으로 작동 할 수 있지만 연관 연산에 대해 동일한 결과를 반환해야합니다. 예를 들어 :'foldl1 (++) xs == foldr1 (++) xs'는 하스켈에서'True'입니다. –

답변

4

내가했던 방법을 구현하는 것이 참으로 reduceRight에 대한 더 많은 이해가되지 않습니다?

아마도. 그러나 JavaScript 배열 반복자은 순수 함수 프로그래밍 백그라운드에서 가져온 것이 아닙니다.

reduceRight이 내가 수행 한 방식으로 구현되지 않은 이유는 무엇입니까?

동일한 매개 변수 순서를 갖는 것이 더 간단하기 때문에 (축약하기가 쉽기 때문에) 누적 기가 항상 처음입니다.

배열의 기본 연산은 항상 0에서 n-1까지 반복되는 reduce입니다. 하스켈에서만 재귀 적으로 빌드 된리스트 인 foldr이 더욱 의미가있다. (build 이중성을 가지며, 무한리스트에서 잘 작동한다 ...). 명명이 reduce + reduceLeft하지 얼마나

그런 다음 reduceRight이 배의 작업을 반전하지 않습니다 ...주의, 그냥 반복 순서를 반전시킵니다. 이것은 일반적 예를 들면, 문서 및 튜토리얼에 확실한 가이드을 설명하는 방법도 있습니다 :

reduceRight()처럼 작동 reduce(), 그것은 가장 높은에서 배열을 처리하는 것을 제외하고. 그것은 단지 시작 단부를 뒤집어 및 스텝 값을 무효화 :

또한 JS 1.8 Mozilla's array extrasreduce/reduceRightfirst implementation은 (Bug 363040 참조)이 방법을 따랐다.

ES4 사양의 경우 notes of Dave Herman은 이러한 생각을 따랐습니다. Haskell에 대해 언급하고 있지만, 전체 문서는 callback의 매개 변수 순서를 전혀 다루지 않습니다. 아마도 하스켈의 흔하지 않은 구문이나 표준 타입의 이름에서 별개의 순서가 없어져서 두 서명이 모두 (a -> b -> …으로 시작되었다. 더 많은 논의가 missing thisObject parameter에 들어갔다.

일부 관련 발췌 : [접근의]

장점 : 파이썬 => 파이썬 커뮤니티 마음 점유율과 같은

  • 배의 전체 일반성 (왼쪽)
  • LSO 나는 대부분의 사람들은 일반적으로 반복하기 때문에, 더
    직관적 감소의 왼쪽에서 오른쪽으로 버전을 찾을 추측에는 요

간단한 첫 번째 요소는 기초 요소가 간단한 경우를 만들 배열을 왼쪽에서 오른쪽으로 파이썬이 그렇습니다.

내가하지 모든 작업이 연관이기 때문에 또한
,뿐만 아니라 reduceRight를 제공하는 것이 중요하다고 생각하고, 때때로 사람들은 오른쪽에서 왼쪽으로 이동 해야합니다.

그리고 마지막으로는, 그게 무슨 got into the EcmaScript spec입니다 :

배열 엑스트라가 : 사양 그것은 현재 FF에서 지원하는 방식이

관련 문제