대수학에서는 일상적인 개념 형성에서와 마찬가지로 몇 가지 필수 특성으로 사물을 그룹화하고 특정 다른 특성을 생략하여 추상화가 형성됩니다. 추상화는 유사성을 나타내는 단일 기호 또는 단어로 통합됩니다. 우리 는 차이점 을 추상화 한다고 말하지만 이것은 실제로 우리가 유사점으로 통합 된다는 것을 의미 합니다.
예를 들어, 숫자의 합을 취하는 프로그램을 고려 1
, 2
및 3
:
val sumOfOneTwoThree = 1 + 2 + 3
이 프로그램은 매우 추상적이지 않기 때문에 그다지 흥미롭지 않습니다. 단일 기호 아래에 모든 숫자 목록을 통합하여 합산하는 숫자를 추상화 할 수 있습니다 ns
.
def sumOf(ns: List[Int]) = ns.foldLeft(0)(_ + _)
그리고 우리는 그것이 List라는 것도 특별히 신경 쓰지 않습니다. List는 특정 유형 생성자 (유형을 취하고 유형을 반환)이지만 원하는 필수 특성 (접을 수 있음)을 지정하여 유형 생성자를 추상화 할 수 있습니다.
trait Foldable[F[_]] {
def foldl[A, B](as: F[A], z: B, f: (B, A) => B): B
}
def sumOf[F[_]](ns: F[Int])(implicit ff: Foldable[F]) =
ff.foldl(ns, 0, (x: Int, y: Int) => x + y)
그리고 우리는 우리가 접을 수있는 모든 것에 Foldable
대한 암시 적 인스턴스를 가질 List
수 있습니다.
implicit val listFoldable = new Foldable[List] {
def foldl[A, B](as: List[A], z: B, f: (B, A) => B) = as.foldLeft(z)(f)
}
val sumOfOneTwoThree = sumOf(List(1,2,3))
또한 연산과 피연산자의 유형을 모두 추상화 할 수 있습니다 .
trait Monoid[M] {
def zero: M
def add(m1: M, m2: M): M
}
trait Foldable[F[_]] {
def foldl[A, B](as: F[A], z: B, f: (B, A) => B): B
def foldMap[A, B](as: F[A], f: A => B)(implicit m: Monoid[B]): B =
foldl(as, m.zero, (b: B, a: A) => m.add(b, f(a)))
}
def mapReduce[F[_], A, B](as: F[A], f: A => B)
(implicit ff: Foldable[F], m: Monoid[B]) =
ff.foldMap(as, f)
이제 우리는 꽤 일반적인 것을 가지고 있습니다. 이 방법 mapReduce
은 접을 수 있고 모노 이드이거나 하나로 매핑 될 F[A]
수 있다는 것을 증명할 수 있는 모든 것을 F
접을 A
것입니다. 예를 들면 :
case class Sum(value: Int)
case class Product(value: Int)
implicit val sumMonoid = new Monoid[Sum] {
def zero = Sum(0)
def add(a: Sum, b: Sum) = Sum(a.value + b.value)
}
implicit val productMonoid = new Monoid[Product] {
def zero = Product(1)
def add(a: Product, b: Product) = Product(a.value * b.value)
}
val sumOf123 = mapReduce(List(1,2,3), Sum)
val productOf456 = mapReduce(List(4,5,6), Product)
우리는 모노 이드와 폴더 블 을 추상화했습니다 .