답변:
실제 답변을 제공하기 전에 몇 가지 언급 할 사항이 있습니다.
left
축소와 접기의 차이점에 관한 것입니다.질문으로 돌아 가기 :
여기에 서명이 있습니다 foldLeft
( foldRight
내가 만들려고했던 시점 일 수도 있음 ).
def foldLeft [B] (z: B)(f: (B, A) => B): B
그리고 여기에 서명이 있습니다 reduceLeft
(다시 방향은 중요하지 않습니다)
def reduceLeft [B >: A] (f: (B, A) => B): B
이 두 가지는 매우 비슷해 보이므로 혼동을 일으켰습니다. reduceLeft
의 특별한 경우이다 foldLeft
(방식에 의해 당신이 것을 때때로 그들 중 하나를 사용하여 같은 일을 표현할 수는).
당신이 호출 할 때 reduceLeft
A의 말을 List[Int]
말 그대로 형식이 될 것입니다 단일 값으로 정수의 전체 목록을 줄일 수 있습니다 Int
(또는의 슈퍼 Int
따라서 [B >: A]
).
foldLeft
say 를 호출 List[Int]
하면 전체 목록 (종이 롤링 상상)을 단일 값으로 접을 수 있지만이 값은 Int
(따라서 [B]
) 관련이 없어도 됩니다.
예를 들면 다음과 같습니다.
def listWithSum(numbers: List[Int]) = numbers.foldLeft((List.empty[Int], 0)) {
(resultingTuple, currentInteger) =>
(currentInteger :: resultingTuple._1, currentInteger + resultingTuple._2)
}
이 방법은 소요 List[Int]
와 반환 Tuple2[List[Int], Int]
또는 (List[Int], Int)
. 합계를 계산하고 정수 목록과 합계를 가진 튜플을 반환합니다. 그건 그렇고 우리가 foldLeft
대신 사용했기 때문에 목록이 뒤로 반환 됩니다 foldRight
.
시계 하나는 그들 모두를 지배 접어 깊이 설명에서 더 많은 것을 위해.
B
슈퍼 타입 이 설명 이 A
됩니까? 같은 것 B
사실의 하위 유형이어야한다 A
,하지 슈퍼. 예를 들어, s Banana <: Fruit <: Food
의 목록이 있으면 Fruit
s를 포함하고있는 것으로 보이지만 Banana
s 가 포함되어 있으면 Food
유형이 Food
맞습니까? 따라서이 경우 B
수퍼 타입이 A
이고 B
s 및 A
s 를 모두 포함 하는 목록이있는 경우 목록이 B
아닌 유형이어야합니다 A
. 이 불일치를 설명 할 수 있습니까?
List[Banana]
것이 단일 Banana
또는 단일 Fruit
또는 단일로 축소 될 수 있다는 것 Food
입니다. 때문에 Fruit :> Banana
와`음식 :> 바나나 '.
Banana
가 포함되어있을 수 있습니다. Fruit
" 로 해석 되어 이해가되지 않습니다. 당신의 설명은 의미가 있습니다- f
전달 되는 함수는 reduce()
a Fruit
또는 a를 초래할 수 있습니다 Food
. 이는 B
서명에서 서브 클래스가 아닌 수퍼 클래스 여야 함을 의미 합니다.
reduceLeft
편리한 방법 일뿐입니다. 그것은
list.tail.foldLeft(list.head)(_)
reducelft
그래도 철자를 수정하고 싶을 수도 있습니다
fold
빈 목록에서 작동하지만 reduce
그렇지 않은 이유를 강조 합니다 .
foldLeft
더 일반적으로 사용하면 원래 입력 한 것과 완전히 다른 것을 reduceLeft
생성하는 데 사용할 수 있습니다 . 반면 에 동일한 유형 또는 수퍼 유형의 콜렉션 유형의 최종 결과 만 생성 할 수 있습니다. 예를 들면 다음과 같습니다.
List(1,3,5).foldLeft(0) { _ + _ }
List(1,3,5).foldLeft(List[String]()) { (a, b) => b.toString :: a }
는 foldLeft
최종 결과 절첩 폐쇄 (제 시간의 초기 값을 사용하여)하고, 다음 값을 적용한다.
reduceLeft
반면에 먼저 목록에서 두 값을 결합하여 클로저에 적용합니다. 다음으로 나머지 값을 누적 결과와 결합합니다. 보다:
List(1,3,5).reduceLeft { (a, b) => println("a " + a + ", b " + b); a + b }
목록이 비어 있으면 foldLeft
초기 값을 올바른 결과로 표시 할 수 있습니다. reduceLeft
반면에 목록에서 하나 이상의 값을 찾을 수없는 경우 유효한 값이 없습니다.
참고 reduceLeft
로 빈 용기에 다음과 같은 오류가 발생하면 오류가 발생합니다.
java.lang.UnsupportedOperationException: empty.reduceLeft
사용할 코드 재 작업
myList foldLeft(List[String]()) {(a,b) => a+b}
하나의 가능한 옵션입니다. 또 다른 방법은 reduceLeftOption
옵션 래핑 된 결과를 반환하는 변형 을 사용하는 것입니다.
myList reduceLeftOption {(a,b) => a+b} match {
case None => // handle no result as necessary
case Some(v) => println(v)
}
에서 스칼라 함수 프로그래밍 원칙 (마틴 오더 스키) :
이 기능
reduceLeft
은보다 일반적인 기능으로 정의됩니다foldLeft
.
foldLeft
는 빈 목록에서 호출 될 때 반환되는 추가 매개 변수로 accumulator를reduceLeft
취 합니다.z
foldLeft
(List (x1, ..., xn) foldLeft z)(op) = (...(z op x1) op ...) op x
[와 반대로 reduceLeft
, 빈 목록에서 호출되면 예외가 발생합니다.]
이 과정 (강의 5.5 참조)은 이러한 기능의 추상 정의를 제공하며, 이는 패턴 일치 및 재귀 사용과 매우 유사하지만 차이점을 보여줍니다.
abstract class List[T] { ...
def reduceLeft(op: (T,T)=>T) : T = this match{
case Nil => throw new Error("Nil.reduceLeft")
case x :: xs => (xs foldLeft x)(op)
}
def foldLeft[U](z: U)(op: (U,T)=>U): U = this match{
case Nil => z
case x :: xs => (xs foldLeft op(z, x))(op)
}
}
주 foldLeft
유형의 값 반환 U
반드시 같은 형식이 아닙니다, List[T]
하지만 reduceLeft리스트와 동일한 유형)의 값을 반환합니다.
fold / reduce로 무엇을하고 있는지 이해하려면 http://wiki.tcl.tk/17983 아주 좋은 설명을 확인하십시오 . 접기의 개념을 얻으면 reduce는 위의 답변과 함께 나타납니다 : list.tail.foldLeft (list.head) (_)