In der Algebra wie in der alltäglichen Konzeptbildung werden Abstraktionen gebildet, indem Dinge nach bestimmten wesentlichen Merkmalen gruppiert und ihre spezifischen anderen Merkmale weggelassen werden. Die Abstraktion wird unter einem einzigen Symbol oder Wort vereinheitlicht, das die Ähnlichkeiten bezeichnet. Wir sagen , dass wir abstrakt über die Unterschiede, aber das wirklich bedeutet , dass wir die Integration von den Ähnlichkeiten.
Betrachten wir zum Beispiel ein Programm, das die Summe der Zahlen nimmt 1
, 2
und 3
:
val sumOfOneTwoThree = 1 + 2 + 3
Dieses Programm ist nicht sehr interessant, da es nicht sehr abstrakt ist. Wir können über die Zahlen, die wir summieren, abstrahieren , indem wir alle Listen von Zahlen unter einem einzigen Symbol integrieren ns
:
def sumOf(ns: List[Int]) = ns.foldLeft(0)(_ + _)
Und es ist uns auch nicht besonders wichtig, dass es sich um eine Liste handelt. List ist ein bestimmter Typkonstruktor (nimmt einen Typ und gibt einen Typ zurück), aber wir können über den Typkonstruktor abstrahieren, indem wir angeben, welches wesentliche Merkmal wir wollen (dass es gefaltet werden kann):
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)
Und wir können implizite Foldable
Instanzen für List
und alles andere haben, was wir folden können.
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))
Darüber hinaus können wir sowohl die Operation als auch den Typ der Operanden abstrahieren :
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)
Jetzt haben wir etwas ganz Allgemeines. Die Methode mapReduce
wird alles falten, F[A]
vorausgesetzt, wir können beweisen, dass F
es faltbar ist und dass A
es sich um ein Monoid handelt oder dass es in eines abgebildet werden kann. Beispielsweise:
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)
Wir haben über Monoide und Faltblätter abstrahiert .
Set
oder einem anderen faltbaren Typ machen würden. Ein Beispiel mit aString
und Verkettung wäre auch ziemlich cool.In erster Näherung bedeutet die Möglichkeit, etwas zu "abstrahieren", dass Sie, anstatt dieses Objekt direkt zu verwenden, einen Parameter daraus erstellen oder es auf andere Weise "anonym" verwenden können.
Mit Scala können Sie über Typen abstrahieren, indem Klassen, Methoden und Werte Typparameter und Werte abstrakte (oder anonyme) Typen haben.
Mit Scala können Sie über Aktionen abstrahieren, indem Methoden Funktionsparameter haben.
Mit Scala können Sie Features abstrahieren, indem Sie Typen strukturell definieren.
Mit Scala können Sie über Typparameter abstrahieren, indem Sie Typparameter höherer Ordnung zulassen.
Mit Scala können Sie Datenzugriffsmuster abstrahieren, indem Sie Extraktoren erstellen.
Mit Scala können Sie über "Dinge, die als etwas anderes verwendet werden können" abstrahieren, indem Sie implizite Konvertierungen als Parameter zulassen. Ähnlich verhält es sich mit Typklassen mit Haskell.
Mit Scala können Sie (noch) nicht über Klassen abstrahieren. Sie können eine Klasse nicht an etwas übergeben und dann mit dieser Klasse neue Objekte erstellen. Andere Sprachen erlauben die Abstraktion über Klassen.
("Monaden abstrakt über Typkonstruktoren" ist nur auf sehr restriktive Weise wahr. Lassen Sie sich nicht aufhängen, bis Sie Ihren "Aha! Ich verstehe Monaden !!" - Moment haben.)
Die Fähigkeit, über einen Aspekt der Berechnung zu abstrahieren, ermöglicht im Grunde die Wiederverwendung von Code und die Erstellung von Funktionsbibliotheken. Mit Scala können viel mehr Dinge abstrahiert werden als mit mehr Mainstream-Sprachen, und Bibliotheken in Scala können entsprechend leistungsfähiger sein.
quelle
Manifest
oder sogar ein übergebenClass
und mithilfe der Reflexion neue Objekte dieser Klasse instanziieren.Eine Abstraktion ist eine Art Verallgemeinerung.
http://en.wikipedia.org/wiki/Abstraction
Nicht nur in Scala, sondern in vielen Sprachen sind solche Mechanismen erforderlich, um die Komplexität zu verringern (oder zumindest eine Hierarchie zu erstellen, die Informationen in leichter verständliche Teile aufteilt).
Eine Klasse ist eine Abstraktion über einen einfachen Datentyp. Es ist wie ein Basistyp, verallgemeinert sie jedoch tatsächlich. Eine Klasse ist also mehr als ein einfacher Datentyp, hat aber viele Gemeinsamkeiten.
Wenn er "abstrahieren über" sagt, meint er den Prozess, durch den Sie verallgemeinern. Wenn Sie also Methoden als Parameter abstrahieren, verallgemeinern Sie den Vorgang. Anstatt Methoden an Funktionen zu übergeben, können Sie beispielsweise eine verallgemeinerte Methode erstellen, um damit umzugehen (z. B. Methoden überhaupt nicht übergeben, sondern ein spezielles System aufbauen, um damit umzugehen).
In diesem Fall meint er speziell den Prozess der Abstraktion eines Problems und der Schaffung einer oop-ähnlichen Lösung für das Problem. C kann nur sehr wenig abstrahieren (Sie können es tun, aber es wird sehr schnell chaotisch und die Sprache unterstützt es nicht direkt). Wenn Sie es in C ++ geschrieben haben, können Sie oop-Konzepte verwenden, um die Komplexität des Problems zu reduzieren (nun, es ist dieselbe Komplexität, aber die Konzeptualisierung ist im Allgemeinen einfacher (mindestens wenn Sie lernen, in Abstraktionen zu denken)).
Beispiel: Wenn ich einen speziellen Datentyp benötigte, der einem Int ähnelte, aber beispielsweise eingeschränkt war, konnte ich ihn abstrahieren, indem ich einen neuen Typ erstellte, der wie ein Int verwendet werden konnte, aber die Eigenschaften hatte, die ich brauchte. Der Prozess, den ich verwenden würde, um so etwas zu tun, würde als "Abstraktion" bezeichnet werden.
quelle
Hier ist meine enge Show und Tell Interpretation. Es ist selbsterklärend und läuft in der REPL.
quelle
Die anderen Antworten geben bereits eine gute Vorstellung davon, welche Arten von Abstraktionen existieren. Lassen Sie uns die Anführungszeichen einzeln durchgehen und ein Beispiel geben:
Funktion als Parameter übergeben:
List(1,-2,3).map(math.abs(x))
Wirdabs
hier eindeutig als Parameter übergeben.map
selbst abstrahiert über eine Funktion, die mit jedem Listenelement eine bestimmte Spezialität ausführt.val list = List[String]()
Gibt einen Typparameter (String) an. Sie können einen Sammlungstyp schreiben, der stattdessen abstrakte Typelemente verwendet :val buffer = Buffer{ type Elem=String }
. Ein Unterschied besteht darin , dass Sie schreiben müssen ,def f(lis:List[String])...
aberdef f(buffer:Buffer)...
, so der Elementtyp Art „versteckt“ in der zweiten Methode ist.In Swing "passiert" ein Ereignis einfach aus heiterem Himmel, und Sie müssen sich hier und jetzt damit befassen. Mit Ereignisströmen können Sie die gesamte Installation und Verkabelung deklarativer ausführen. Wenn Sie beispielsweise den verantwortlichen Listener in Swing ändern möchten, müssen Sie die Registrierung des alten und des neuen Listeners aufheben und alle wichtigen Details kennen (z. B. Threading-Probleme). Bei Ereignisströmen wird die Quelle der Ereignisse zu einer Sache, die Sie einfach weitergeben können, wodurch sie sich nicht sehr von einem Byte- oder Zeichenstrom unterscheidet und daher ein "abstrakteres" Konzept darstellt.
Die obige Pufferklasse ist bereits ein Beispiel dafür.
quelle
Die obigen Antworten bieten eine hervorragende Erklärung, aber um sie in einem einzigen Satz zusammenzufassen, würde ich sagen:
quelle