300

Programmieren in Scala 17. Juni 2013 G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering 232 / 300 Motivation • Aus Sicht unser...
Author: August Hartmann
21 downloads 0 Views 196KB Size
Programmieren in Scala

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

232 / 300

Motivation

• Aus Sicht unseres Sotwaretechnik-Lehrstuhls:

Scala ist eine der derzeit modernsten Programmiersprachen • KIV wird derzeit nach Scala portiert (fast fertig) • KIV ist dann mit Scala und Java (GUI) programmiert. • Scala unterst¨ utzt Konzepte die vieles mit den Konzepten der

KIV-Spezifikationen gemeinsam haben.

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

233 / 300

Was ist Scala? • Scala ist entwickelt an der Uni Lausanne von Prof. Odersky

http://www.scala-lang.org • Viele Dokus (Tutotial, etc.) kann man dort finden • Eclipse-IDE: //http://www.scala-ide.org • Scala ist eine objektorientierte Sprache • Alle Konzepte von Java (Methoden, Klassen, Vererbung etc.) gibt es

(z.T. in verbesserter Form) auch in Scala • Scala wird in ByteCode der JVM compiliert • Scala unterst¨ utzt auch die Konzepte aus funktionalen Sprachen

(Higher-Order Funktionen Pattern Matching etc.) • Die Syntax von Scala ist etwas anders, und deutlich verbessert

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

234 / 300

Scala: Typen

• Scala kennt wie Java Klassen und generische Klassen • Oberster Typ ist Any statt Object • Scala kennt keine primitiven Typen: • statt int und Integer gibt es nur Int • analog: bool, Boolean ⇒ Boolean, array, Array ⇒ Array • generische Typen werden mit eckigen Klammern geschrieben:

Array[Int] statt Array • Array-Zugriff mit runden Klammern a(i) (statt a[i]) • Fest vordefiniert sind Tupel mit (f¨ ur 3-Tupel) Typ (A,B,C). Sie

werden auch als (a,b,c) konstruiert. Die Felder werden z.B. mit (a,b,c). 2 selektiert (liefert b)

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

235 / 300

Scala: Methodendefinition • Scala kennt wie Java statische und dynamische Methoden • Java:

type method(argty1 arg1, argty2 arg2, ...){ body } • Scala:

def method(arg1:argty1,arg2:argty, ...):type = { body } • Der Typ void heisst Unit in Scala • Methoden ohne Resultat k¨ onnen vereinfacht als

def method(arg1:argty1, ... ) { body } geschrieben werden (kein Typ und kein Gleichheitszeichen) 17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

236 / 300

Scala: Methodenaufruf • Aufruf wie in Java f¨ ur statische und dynamische Methoden

type . smethod (arg1, arg2, . . . ) object . dmethod (arg1, arg2, . . . ) • Bei Methoden ohne Argumente d¨ urfen Leerklammern weggelassen

werden (auch schon bei der Definition) • Konvention: Leerklammern weglassen gdw. keine Seiteneffekte:

z.B. Selektoren (“getter”) und Tests: list.length, list.isEmpty • Vorteil: Feldzugriff kann lokal auf get-Methode (gleichen Namens)

¨ ge¨andert werden (keine Anderung in anderen Klassen!) • Dynamischen Methoden mit einem Argument darf man mit

object method arg aufrufen (Infix: weder Punkt noch Klammern!) • Vorteil: +, * etc. haben keine Sonderrolle mehr

(sie k¨onnen auch u ¨berladen werden). 17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

237 / 300

Ausprobieren von Scala • Scala kann man wie Java compilieren und ein Programm

main(arglist:Array[String]):Unit in einem object ausf¨ uhren. • Scala kann aber auch mit einem Kommandozeileninterpreter (entweder von innerhalb Eclipse oder standalone) bedienen • Aufruf von scala gibt scala>-prompt • Eintippen von Ausdr¨ ucken wertet diese aus scala> "Hello scala> 7 scala> 2 scala> 6

"Hello" + " World!" World!" 3 + 4 new Array(4,5).length new Array(5,6)(1)

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

238 / 300

Scala: Felder und lokale Variablen

• Scala unterscheidet bei Feldern und Variablen u ¨berschreibbare (var)

und nicht u ¨berschreibbare (val; Java: final) • nicht u ¨berschreibare Felder/Variablen val x:Int = 5 • u ¨berschreibare Felder/Variablen var x:Int = 5 • Scala implementiert eine Typinferenz:

F¨ ur die meisten Variablen und initialisierten Felder kann die Typangabe wegfallen. • F¨ ur das obige Beispiel: val x = 5 ist ok

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

239 / 300

Scala: Methodenr¨umpfe

• Scala kennt keinen Unterschied zwischen Statement und Expression. • Statements sind einfach Expressions vom Typ Unit • Deshalb ist mischen erlaubt, z.B.:

val x = if (y > 5) { val y = 3; y + 2} else 5 • Der ?-Operator von Java ist in Scala u ussig ¨berfl¨ • In Scala werden Strichpunkte nur ben¨ otigt, wenn zwei Statements

auf derselben Zeile stehen (sehr selten) • Zeilenumbruch f¨ ugt (wo sinnvoll) implizit einen Strichpunkt ein • Wenn return expr das letzte Statement einer Methode ist, darf nur

expr geschrieben werden.

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

240 / 300

Scala: Beispele f¨ur Methoden

• Fakult¨ atsfunktion:

def fac(x:Int):Int = {if (x == 0) 0 else fac(x - 1)} • L¨ ange (wie in Listenklasse vordefiniert):

def length:Int = {if (isEmpty) 0 else tail.length + 1} • Letztere Funktion w¨ urde in Java so aussehen:

int length() {if (isEmpty) return 0; else return tail.length() + 1;}

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

241 / 300

Scala: Klassendefinitionen (1) • Java Klassen enthalten sowohl statische als auch dynamische

Methoden • Scala teilt die Methoden auf in dynamische in der Klasse und statische, die im sog. companion object gleichen Namens stehen • Beide m¨ ussen in dieselbe Datei, eines von beiden darf fehlen • Wenn nur object ⇒ Singleton. object A { def staticmethod(arg:Int):Int = { 2 * arg } } class A { val field = 5 def dynamicmethod(arg:Int):Int = { this.field + arg} } 17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

242 / 300

Scala: Klassendefinitionen (2)

• Java Klassen haben immer einen (h¨ aufig nutzlosen) nullstelligen

Konstruktor • meist muss einer definiert werden, der einfach nur Felder initialisiert. • In Scala stattdessen: Felder, die im Konstruktor initialisiert werden

sollen, als Argumente der Klasse. Kein nullstelliger Konstruktor.

class A(val field1:Int, var field2:Int) {...} ergibt als m¨oglichen Konstruktoraufruf new A(3,5). Ein nullstelliger Konstruktoraufruf ist nicht m¨ oglich.

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

243 / 300

Scala: Abstrakte Datentypen (1) Scala unterst¨ utzt freie Datentypen analog zu KIV-Specs. Beispiel: arithmetische Ausdr¨ ucke. sealed abstract classed AExp case class Binop(val e1:AExp, val str:String, val e2:AExp) extends AExp case class Unop(val str:String, val e:AExp) extends AExp case class Val(val v:Int) extends AExp case class Var(val id:String) extends AExp

erlaubt zu schreiben: Binop(Var("x"),"+",Unop("-",Val(4))))

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

244 / 300

Scala: Abstrakte Datentypen (2) • Ein abstrakter Datentyp besteht aus einer abstrakten

(Summen-)Klasse (AExp) und einer Anzahl Unterklassen (Summanden; hier Binop, Unop, Val, Id) • Alle Klassen werden zusammen in die Datei AExp

der Summenklasse geschrieben • sealed ⇒ keine (weiteren) Unterklassen in anderen Dateien • case class: erlaubt Konstruktoraufruf ohne Schl¨ usselwort new

(und Pattern matching; siehe sp¨ater) • Die Felder sind meist nicht schreibbar (val),

sie werden nur vom Konstruktor initialisiert (“immutable” datatype; entspricht algebraischen Datentypen). • Gleichheit (i.e. ==) vergleicht case classes strukturell (nicht wie in

Java auf Referenz-Gleichheit). 17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

245 / 300

Scala: Listen (1) Listen sind ein vordefinierter freier Datentyp sealed abstract class List[+A] case class ::[A](val head:A, tail:List[A]) extends List[A] case object Nil extends List[Nothing]

erlaubt Konstruktion mit 1::2::Nil Bem: eigentlich ::(1,::(2::Nil)), aber “::” ist auch eine Infixfunktion auf Listen, die mit Doppelpunkt endet. Solche Infixfunktionen drehen die Argumentreihenfolge um!

Alternativ: List(1,2) (durch Aufruf der statischen Methode List mit variabler Argumentzahl im companion object der Klasse List)

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

246 / 300

Scala: Listen (2) ¨ • Listen erlauben kein Uberschreiben des head oder tail. • Listen sind kovariant (das bedeuet das + vor dem Typparameter):

jedes x:List[Int] ist auch ein x:List[Any] jedes x:List[Binop] ist auch ein x:List[AExp] • allgemein x:List[type1] ist Subtyp von x:List[type2] falls type1 ein

Subtyp (Unterklasse) von type2 ist. • Arrays sind dagegen nicht kovariant (weil modifizierbar) • Nothing ist der leere Typ ohne jedes Element (Subtyp von jedem

Typ). Nil ist deshalb vom Typ List[type] f¨ ur jeden Typ type • Listen haben viele vordefinierte Funktionen, u.a. ++ (append), x(i)

(get f¨ ur das i-te Element, 0-basiert); siehe scaladoc

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

247 / 300

Scala: Pattern Matching • Scala erlaubt Pattern Matching f¨ ur ADTs • match verallgemeinert Java’s switch. • Methode allids (in Klasse AExp) sammelt

alle vorkommenden Variablen des Ausdrucks • Funktion ++ h¨ angt Listen aneinander. • Ein Underscore steht f¨ ur wildcard (beliebig) def allids:List[String] = { this match { case Var(id) => List(id) case Binop(e1, ,e2) => e1.allids ++ e2.allids case Unop( ,e0) => allids(e0) case Val( ) => Nil } } Binop(Var(”x”),”+”,Val(4)).allids ergibt List(”x”) 17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

248 / 300

Scala: Higher-Order Funktionen • Scala erlaubt Higher-Order Functions,

i.e. Funktionen, die Funktionen als Argumente bekommen. • Funktionstypen werden A => B geschrieben. • Beispiel: Funktion map (in Klasse List[A] definiert) wendet eine Funktion f auf alle Listenelemente an def map[B](f:A => B):List[B] = { this match { Nil => Nil x :: xs => f(x) :: xs.map(f) }} oder alternativ: def map[B](f:A => B):List[B] = { if (isEmpty) Nil else f(head) :: tail.map(f) } 17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

249 / 300

Scala: lambda-Abstraktionen • Das Funktionsargument von map kann eine Funktion sein, die mit

def definiert wurde • Da die Funktion meist nur einmal verwendet wird, gibt es auch die

M¨oglichkeit, sie als lambda-Abstraktion anzugeben • x:Int => x + 1 ist die Funktion, die eins addiert • (x:Int,y:Int) => x + y ist die Additionsfunktion • Verwendung z.B mit map:

List(1,2,3).map((x:Int) => 2 * x) ergibt List(2,4,6) • Kurzschreibweise: e(_) statt (x:Int => e(x))

(manchmal ist Typangabe notwendig: e(_:Int) • Beispiel: List((1,2),(4,5)).map(_._1) == List(1,4)

(mit Selektor . 1 f¨ ur Paare)

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

250 / 300

Scala: Datentyp Map

• Eine Map bildet endlich viele Schl¨ ussel (keys) auf Werte (values) ab. • Analog zu Liste von Paaren, aber keine doppelten Schl¨ ussel • Paare kann man sowohl mit (a,b) als auch mit a -> b konstruieren. • Konstruktion aus Paaren mit Map("x" -> 3, "y" -> 4) • Das letzte z¨ ahlt: Map("x" -> 3, "x" -> 4) == Map("x" -> 4) • Zugriff u ¨ber Map("x" -> 3, "y" -> 4)("x") ergibt 3 • Addieren: Map("x" -> 3) + ("y" -> 4) ergibt

Map("x" -> 3, "y" -> 4)("x") • L¨ oschen mit Map("x" -> 3, "y" -> 4) - "x" gibt

Map("y" -> 4)

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

251 / 300

Scala: viele weitere Features

Scala hat noch viele andere Features, auf die wir hier nicht eingehen: • lazy Funktionen und Felder • interfaces erweitert scala zu traits.

Diese d¨ urfen auch Code definieren. • implizite Argumente • selbstdefiniertes Pattern Matching • erweiterte generische Syntax f¨ ur Schleifen • ...

17. Juni 2013

G. Schellhorn, D. Haneberg: Formale Methoden im Software Engineering

252 / 300