1. ホーム
  2. scala

[解決済み] アブストラクトオーバーとはどういう意味ですか?

2023-01-19 03:51:38

質問

Scalaの文献でしばしば "抽象オーバー" というフレーズに出会いますが、その意図がわかりません。 例えば Martin Oderskyは次のように書いています。

メソッド(または "関数" )をパラメータとして渡すこともできますし、次のようにすることもできます。 を抽象化する を抽象化することもできます。パラメータとして型を指定することができます。 を抽象化する を抽象化することもできます。

別の例として Observerパターンを廃止します。 の論文を参照してください。

イベントストリームがファーストクラスの値であることから、次のことが可能になります。 を抽象化できることです。 を抽象化できることです。

一次ジェネリックが"abstract over types"、モナドが"abstract over type constructors"と書かれているのを読んだことがあります。 また、このようなフレーズを ケーキの型紙 . そのような多くの例の一つを引用します。

抽象的な型のメンバは、以下のような柔軟な方法を提供します。 を抽象化する柔軟な方法を提供します。 を抽象化する柔軟な方法を提供します。

関連するスタックオーバーフローの質問でさえ、この用語を使用しています。 パラメータ化された型の上に存在論的に抽象化できない..."

では..."abstract over"は実際には何を意味するのでしょうか?

どのように解決するのですか?

代数学では,日常の概念形成と同様に,ある本質的な特徴によって物事をグループ化し,その固有の他の特徴を省くことによって抽象化する。抽象化されたものは、類似性を示す1つの記号や単語の下に統一されます。私たちは次のように言う。 を抽象化する と言いますが、これは本当に私たちが を統合していることになります。 を意味します。

例えば、数値の和をとるプログラムを考えてみましょう。 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)
}

implicit val setFoldable = new Foldable[Set] {
  def foldl[A, B](as: Set[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(Set(4,5,6), Product)

私たちは を抽象化し モノイドとフォールダブルを抽象化しました。