Scala

Scala #

https://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/ https://github.com/milessabin/shapeless http://nerd.kelseyinnis.com/blog/2013/01/07/resources-for-getting-started-with-functional-programming-and-scala/ http://danielwestheide.com/scala/neophytes.html

Typklassen (Type classes) #

Definition #

Eine Typklasse C definiert das Verhalten eines Typs T, indem sie Operationen vorgibt, welche T unterstützen muss. Dabei muss T kein Attribut (member) der Typklasse C sein. Stattdessen kann der Entwickler für einen Typ die Zugehörigkeit zu C festlegen, indem er die Operationen implementiert. Typklassen unterstützen damit Ad-hoc und retroaktiver Polymorphismus.

Implementierung #

Typklassen in Scala erfordern mehrere Schritte.

  • Erstens die Typklasse selbst, die in der Regel zustandslos ist, also nur mit den gegebenen Parametern operiert. Bsp.:
    object Math {
        // Define default error message
        import annotation.implicitNotFound
        @implicitNotFound("No member of type class NumberLike in scope for ${T}")
    	trait NumberLike[T] {
    		def plus(x: T, y: T): T
    		def divide(x: T, y: Int): T
    		def minus(x: T, y: T): T
    	}
    }
    
  • Zweitens (nicht zwingend, aber vorteilhaft) eine Reihe von default members:
    object Math {
    	// Define default error message
    	    import annotation.implicitNotFound
    	trait Number Like[T] { ... }
    	object Number Like {
    		implicit object NumberLikeDouble extends NumberLike[Double] {
    			def plus(x: Double, y: Double); Double = x + y
    			def divide(x: Double, y: Int): Double = x / y
    			def minux(x: Double, y: Double): Double = x - y
    		}
    		implicit object NumberLikeInt extends NumberLike[Int] {
    			def plus(x: Int, y: Int): Int = x + y
    			def divide(x: Int, y: Int): Int = x / y
    			def minus(x: Int, y: Int): Int = x - y
    		}
    	}
    }
    
  • Drittens die konkrete Anwendung:
    object Statistics {
    	import Math.NumberLike
    	def mean[T](xs: Vector[T])(implicit ev: NumberLike[T]): T =
    		ev.divide(xs.reduce(ev.plus(_, _)), xs.size)
    	}
    

Bei einem impliziten Parameter mit nur einem Typparameter kann dies auch mit einem sog. context bound abgekürzt werden: scala object Statistics { import Math.NumberLike def mean[T : NumberLike](xs: Vector[T]): T = ev.divide(xs.reduce(ev.plus(_, _)), xs.size) }

Anwendungsfälle #

  • Numeric- und Ordering-Typklasse in der Standardbibliothek
  • Objekt-Serialisierung und -Deserialisierung in Bibliotheken von Drittanbietern (bspw. JSON): Für eigene Klassen können, wenn sie member einer Formattierungs-Typklasse sind, Wege definiert werden, wie sie in Standardformate (JSON, XML etc.) serialisiert werden
  • Mappings zwischen Scala-Typen und Typen, die von einem bestimmten Datenbanktreiber unterstützt werden, werden ebenfalls oftmals mit Typklassen gestalt- und erweiterbar gemacht.

Weitere Ressourcen #

Allgemeine Onlineressourcen #