9

Scalaz는 Boolean, Option[_], Validation[_, _], Either[_, _] 등과 같이 다양한 ADT에 대해 fold이라는 메서드를 제공합니다.이 메서드는 기본적으로 주어진 ADT에 대한 모든 가능한 경우에 해당하는 함수를 사용합니다. 즉, 패턴 매칭이 아래 :옵션에서 접기, 둘 중 하나 등의 관계는 무엇이며 트래 버블에서 접기는 무엇입니까?

x.fold(f, g, ..., z) 

일부 예 :

x match { 
    case Case1(a, b, c) => f(a, b, c) 
    case Case2(a, b) => g(a, b) 
    . 
    . 
    case CaseN => z 
} 

는 동등하다 동시에

scala> (9 == 8).fold("foo", "bar") 
res0: java.lang.String = bar 

scala> 5.some.fold(2 *, 2) 
res1: Int = 10 

scala> 5.left[String].fold(2 +, "[" +) 
res2: Any = 7 

scala> 5.fail[String].fold(2 +, "[" +) 
res6: Any = 7 

동일한 함께 동작 존재 Traversable[_] 유형의 이름으로 요소에서 특정 작업을 수행하는 모음을 탐색하고 결과 값을 누적합니다. fold/catamorphism - 예를 들어,

scala> List(2, 90, 11).foldLeft("Contents: ")(_ + _.toString + " ") 
res9: java.lang.String = "Contents: 2 90 11 " 

scala> List(2, 90, 11).fold(0)(_ + _) 
res10: Int = 103 

scala> List(2, 90, 11).fold(1)(_ * _) 
res11: Int = 1980 

왜이 두 작업은 동일한 이름으로 식별? 나는 두 사람 사이에 어떤 유사점이나 관계를 보지 못한다. 내가 뭘 놓치고 있니?

답변

7

나는이 문제가 자신의 구현에 기반한 것이지 유형에 기반한 것이 아니라고 생각합니다.

fold[B] = (noneCase: => B, someCase: A => B) => B 

그래서, Option에, 그것은 B에 어떤 값으로 가능한 모든 경우를 줄이고, 그 반환 : 자들 배 Option '을 생각해 보자, 지금

List[A] = Nil 
     | Cons head: A tail: List[A] 

Option[A] = None 
      | Some el: A 

: 유형이 간단한 표현을 생각해 보자. 이제, List 위해 같은 일을 보자 : 우리가 List[A]에, 거기에 재귀 호출이 그러나

fold[B] = (nilCase: => B, consCase: (A, List[A]) => B) => B 

주,. 우리는 어떻게 든 그 배해야하지만, 우리는 항상 B을 반환하는 List[A]fold[B]을 알고, 그래서 우리는이처럼 다시 작성할 수 있습니다 : 즉

fold[B] = (nilCase: => B, consCase: (A, B) => B) => B 

, 우리는 B으로 List[A]을 대체 있다는 이유 접는는 반환 항상 것입니다 a B이고, 유형 서명이 fold 인 경우 자, 스칼라의 (사용 사례) foldRight에 대한 서명을 입력 보자 :

foldRight[B](z: B)(f: (A, B) ⇒ B): B 

말, 즉 뭔가 당신을 생각 나게 하는가?

+0

아, 재귀 적으로 적용해야합니다! 고마워, 고마워. – missingfaktor

+2

[catamorphism에 대한 위키 피 디아 페이지] (http://en.wikipedia.org/wiki/Catamorphism)는 "기능 프로그래밍에서 기능 변형 프로그래밍에서 임의의 대수 데이터로 알려진 목록의 폴드를 일반화 한 것입니다 초기 대수 (algebras)로 기술 할 수있는 유형 "이라고 설명했다. 그런 다음 Erik Meijer의 논문 "바나나, 렌즈, 봉투 및 철조망을 이용한 기능 프로그래밍"을 설명합니다. 주제에 대해 더 잘 이해할 수 있도록이 신문을 읽어야한다고 생각합니다. – missingfaktor

+1

@missingfaktor, 위키 피 디아 페이지의 끝 부분에는 매우 접근하기 쉬운 것으로 보이는 반증에 관한 6 부분 블로그가 있습니다. 나는 지금 그것을 읽고있다. 그것은 F #이야하지만 당신에게 문제가되지 않을 것이라고 확신합니다. – huynhjl

5

"접는"을 "조작 값을 통해 컨테이너의 모든 값을 종자 값으로 압축"한다고 생각하고 하나의 값을 가질 수있는 컨테이너로 Option을 생각하면이 이해하기 시작합니다.사실

, foldLeft 같은 서명이 당신이 없음 대 빈 목록을 사용하는 경우 정확히 같은 결과를 제공하고, 일부 대 단 하나의 요소와 목록 :

scala> val opt : Option[Int] = Some(10) 
opt: Option[Int] = Some(10) 

scala> val lst : List[Int] = List(10) 
lst: List[Int] = List(10) 

scala> opt.foldLeft(1)((a, b) => a + b) 
res11: Int = 11 

scala> lst.foldLeft(1)((a, b) => a + b) 
res12: Int = 11 

fold입니다 또한 Scala 표준 라이브러리의 ListOption에 동일한 서명으로 정의되어 있습니다 (둘 다 실제로 특성에서 물려 받았다고 생각합니다). 그리고 다시, 당신은 일부에로 싱글 목록에서 동일한 결과를 얻을 :

scala> opt.fold(1)((a, b) => a * b) 
res25: Int = 10 

scala> lst.fold(1)((a, b) => a * b) 
res26: Int = 10 

내가 Option/Either/등의 Scalaz에서 fold 확실 100 % 아니에요, 당신은 거기에 좋은 점을 올립니다. 그것은 꽤 익숙한 "접기"와는 아주 다른 서명과 작동을하는 것처럼 보입니다.