"hello" // string true false // boolean 5 // int 5.5 // double 5f // float 1e30f // float exponential 1.0e-100 // exponential double 0xA // 10 hex int 012 // 10 octal int 1000L // long 'a' // character '\u0041' // unicode character """a multi line "string" """ // multiline escaped string <hello/> // xml 'alright // symbol
var foo = 5 foo = 6 // eksplisitt typet var foo:Int = 5
val x = "Hello" // eksplisitt typet val x:String = "Hello"
def foo:Int = { return 5 }
def foo:Int = { 5 } // siste expression returneres alltid
def foo = { 5 } // return type inference
def foo = 5 // single expression
def something(i:Int):Unit = { println("Do " + i) }
def something(i:Int) { println("Do " + i) } // returnerer alltid Unit (ingen =)
def printSomething() = { println("something") } // () indikerer sideeffekt som konvensjon
val nesting = { def plus(a:Int, b:Int) = a + b val x = { val y = 5 - 3 y - 2 } val z = plus(x, 10) z / 2 }
lazy val person = { println("fra DB") DB.findPersonByPk(5) } println("etter") person.name // etter // fra DB
val a = new String("Hello") val b = new String("Hello") a == b // true (java equals) a eq b // false (java ==)
val msg = "World" s"Hello ${msg}"
class Person { private final String name; private Integer age; public Person(String name, Integer age){ this.name = name; this.age = age; } public String getName(){ return name; } public Integer getAge(){ return age; } public void setAge(Integer age){ this.age = age; } public static Person create30(String name){ return new Person(name, 30); } @Override public String toString(){ return "["+name+","+age+"]"; } }
object Person { def create30(name:String) = new Person(name, 30) } class Person(val name: String, var age: Int){ override def toString = s"[$name,$age]" }
class Person(private val _name: String, private var _age: Int) { def name = _name def age = _age def age_=(a:Int){ _age = a } }
val person = Person.create30("foo") person.name // foo person.age = 29 person.age // 29
val ab = (5, "Hello") val ab = 5 -> "Hello" val abc = (5.5, "World", List(1, 2, 3)) ab._1 // 5 ab._2 // "Hello" abc._3 // List(1, 2, 3)
val list = List(1, 2, 3) val map = Map(1 -> "a", 2 -> "3") val set = Set("a", "b", "c") val vector = Vector("a", "b", "c") val array = Array(1, 2, 3) val range = 1 to 10
val list = List(1, 2, 3) val cons = 1 :: 2 :: 3 :: Nil val map = Map(1 -> "Hello") val helloWorld = map + (2 -> "World") val world = helloWorld - 1 val vector = Vector(1, 2) val appended = vector :+ 3 val prepended = 1 +: appended
case class Person(name:String, age:Int) val people = List(Person("kid-a", 10), Person("kid-b", 12), Person("mom", 42), Person("dad", 43))
var ages = new ListBuffer[Int] for(person <- people){ ages += person.age } val ages = people.map(person => person.age) // List(10, 12, 42, 43)
var kids = new ListBuffer[Person] for(person <- people){ if(person.age < 18) kids += person } val kids = people.filter(person => person.age < 18) // List(Person("kid-a", 10), Person("kid-b", 12))
case class Owner(pets:List[String]) val owners = List(Owner(List("Dog", "Cat")), Owner(List("Fish"))) var pets = new ListBuffer[String] for(owner <- owners){ pets ++= owner.pets } val pets = owners.flatMap(owner => owner.pets) // List("Dog", "Cat", "Fish")
var kids = new ListBuffer[Person] var adults = new ListBuffer[Person] for(person <- people){ if(person.age < 18) kids += person else adults += person } val (kids, adults) = people.partition(person => person.age < 18) val (kids, adults) = people.partition(_.age < 18)
val first10 = list.take(10) val dropped = list.drop(5) case class Person(fornavn:String, etternavn:String) val personer:List[Person] = ... val familier:Map[String, List[Person]] = personer.groupBy(_.etternavn) val fornavn:Map[String, List[String]] = familier.mapValues(personer => personer.map(_.fornavn)) val sortert:Seq[(String, List[String])] = fornavn.toSeq.sortBy(_._1.size)
val list = List(1,2,3) list(0) // of its indexes val map = Map("A" -> 1, "B" -> 2) map("A") // of its keys val set = Set(1,2,3) set(1) // contains
import java.util.HashMap val map = new HashMap[Int, String] map.put(0, null) ... map.get(0) // null map.get(1) // null if(map.containsKey(0)){ return map.get(0) }
val map = Map(1 -> "Hello", 2 -> "World") map.get(1) // Some("Hello") map.get(0) // None map(1) // "Hello" map(0) // java.util.NoSuchElementException
trait Option[+A] { def get:A // eller java.util.NoSuchElementException def getOrElse(a:A):A def map(f:A => B):Option[B] def flatMap(f:A => Option[B]):Option[B] } object None extends Option[Nothing] case class Some[A](value:A) extends Option[A]
class Stuff { /* can be null */ public String getIt(){ ... } }
val stuff:Option[String] = Option(stuff.getIt)
https://github.com/arktekk/scala-kurs-oppgaver/tree/master/buzzword
val length:String => Int = in => in.length def takesAFun(f:String => Int) = { val word = "Hello World" f(word) } takesAFun(length) takesAFun(in => in.length) takesAFun(_.length)
def length(in:String) = in.length takesAFun(length)
val noArg:() => Int = () => 10 def takesNoArg(f:() => Int) = { val anInt = f() 5 + anInt } takesNoArg(noArg) takesNoArg(() => 10)
def callByName(f: => Int) = { val anInt = f 5 + anInt } callByName(5) def callByNameIgnore(f: => Int){ 5 + 10 } callByNameIgnore(throw new Exception("who cares?")) // ingen exception kastet
def multiple(name:String)(age:Int) { println(name + " is " + age + " years old") } multiple("Mr Java")(99) multiple("Mr Scala"){ 5 + 10 }
def debug(name:String)(expr: => String){ val logger = Logger.getLogger(name) if(logger.isDebugEnabled){ logger.debug(expr) } } debug("database"){ DB.reallyHeavyOperation.mkString(",") }
def printIt(name:String) = println("Look, its " + name) val partiallyApplied:String => Unit = printIt _ partiallyApplied("pretty cool") // Look, its pretty cool
val later = new ListBuffer[() => Unit] def register(f: => Unit){ later += f _ } register(println("Hello")) register(println("World")) register(throw new Exception("Oh noes")) println("Go!") later.foreach(f => f()) /* Go! Hello World java.lang.Exception: Oh noes at .... */
trait Mult { def mult(a:Int, b:Int) = a * b } trait Add { def add(a:Int, b:Int) = a + b } object Calc extends Mult with Add Calc.mult(4, Calc.add(1, 2))
trait Rule { def convert(int:Int) = int.toString } trait Fizz extends Rule { override def convert(int:Int) = if(int % 3 == 0) "Fizz" else super.convert(int) } trait Buzz extends Rule { override def convert(int:Int) = if(int % 5 == 0) "Buzz" else super.convert(int) } trait FizzBuzz extends Rule { override def convert(int:Int) = if(int % 3 == 0 && int % 5 == 0) "FizzBuzz" else super.convert(int) }
object FizzTest extends Rule with Fizz (0 to 15).foreach(FizzTest.convert) object BuzzTest extends Rule with Buzz (0 to 15).foreach(BuzzTest.convert) object FizzBuzzTest extends Rule with Fizz with Buzz with FizzBuzz (0 to 15).foreach(FizzBuzzTest.convert) object BuzzFizzTest extends Rule with FizzBuzz with Fizz with Buzz (0 to 15).foreach(BuzzFizzTest.convert)
sealed trait Tree case class Branch(left:Tree, right:Tree) extends Tree case class Leaf(value:Int) extends Tree def sum(tree:Tree):Int = tree match { case Branch(left, right) => sum(left) + sum(right) case Leaf(value) => value } val tree = Branch( Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4))) sum(tree)
case class SomeException(why:String) extends Exception(why) try{ somethingThatCanThrowAnException() } catch { case SomeException(why) => println("Thats why: " + why) case ex:Exception => ex.printStackTrace }
a.k.a 'Enrich my Library'
class PlusMinus(i:Int){ def +- (o:Int) = i-o to o+i } new PlusMinus(5) +- 2 //Range(3, 4, 5, 6, 7)
implicit class PlusMinus(i:Int){ def +- (o:Int) = i-o to o+i } 5 +- 2 //Range(3, 4, 5, 6, 7)
class PlusMinus(i:Int){ def +- (o:Int) = i-o to o+i } implicit def plusMinus(i:Int) = new PlusMinus(int) 5 +- 2 //Range(3, 4, 5, 6, 7)
Skriv ditt eget testrammeverk!
https://github.com/arktekk/scala-kurs-oppgaver/tree/master/testframework
def map [B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[Set[A], B, That]): That
trait Traversable[+A] extends TraversableLike[A, Traversable[A]] with ... { ... } // alle implementasjonene trait TraversableLike[+A, +Repr] { def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = { val b = bf(repr) b.sizeHint(this) for (x <- this) b += f(x) b.result } ... }
object BitSet extends BitSetFactory[BitSet] { def newBuilder = immutable.BitSet.newBuilder implicit def canBuildFrom: CanBuildFrom[BitSet, Int, BitSet] = bitsetCanBuildFrom } object Set extends SetFactory[Set] { def newBuilder[A] = immutable.Set.newBuilder[A] implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Set[A]] = setCanBuildFrom[A] } val b2:BitSet = BitSet(1, 2, 3).map(i => i * 2) val Set[String] = b2.map(i => i.toString)
trait Set[A]{ def map [B](f: (A) ⇒ B): Set[B] // [use case] def map [B, That](f: (A) ⇒ B)(implicit bf: CanBuildFrom[Set[A], B, That]): That }
package lst import collection.mutable.{Builder} import collection.immutable.LinearSeq import collection.LinearSeqOptimized import collection.generic.{GenericTraversableTemplate, SeqFactory} object Lst extends SeqFactory[Lst] { def newBuilder[A]: Builder[A, Lst[A]] = new Builder[A, Lst[A]] { private[this] var lst: Lst[A] = Empty def +=(elem: A) = { lst = Cons(elem, lst) this } def clear() { lst = Empty } def result() = lst } }
sealed trait Lst[+A] extends LinearSeq[A] with GenericTraversableTemplate[A, Lst] with LinearSeqOptimized[A, Lst[A]] { override def companion = Lst } case object Empty extends Lst[Nothing]{ override def isEmpty = true } final case class Cons[A](override val head: A, override val tail: Lst[A]) extends Lst[A]{ override def isEmpty = false }
trait Traversable[+A]{ def foreach[U](f:A => U):Unit }
trait Iterable[+A] extends Traversable[A]{ def iterator:Iterator[A] }
trait Seq[+A] extends Iterable[A]{ def apply(idx:Int):A def length:Int def iterator:Iterator[A] }
object List { def apply[A](elems:A*):List[A] = ... } List(1, 2, 3) object Map { def apply[A, B](elems:(A, B)*):Map[A, B] = ... } Map(1 -> "a", 2 -> "b")
trait Set[A] extends Iterable[A] { def +(elem:A):Set[A] def -(elem:A):Set[A] def contains(elem:A):Boolean def iterator:Iterator[A] }
trait Map[A, +B] extends Iterable[(A, B)]{ def +[B1 >: B](kv:(A, B1)):Map[A, B1] def -(key:A):Map[A, B] def get(key:A):Option[B] def iterator:Iterator[A] }
import collection.mutable._ val myMap = new HashMap[Int, String] with SynchronizedMap[Int, String] val myBuffer = new ListBuffer[String] with SynchronizedBuffer[String] val mySet = new HashSet[String] with SynchronizedSet[String]
sieve of eratosthenes
def sieve(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, sieve(s.tail filterNot { _ % s.head == 0 })) def primes = sieve(Stream.from(2))
Implementer metodene i List selv
https://github.com/arktekk/scala-kurs-oppgaver/tree/master/list
import dispatch._ val request = url("http://www.yr.no/place/Norway/Telemark/Sauherad/Gvarv/forecast_hour_by_hour.xml") val handler = request.as_str val result = Http(handler)
url("http://www.yr.no") / "place" / "Norway" / "Telemark" / "Sauherad" / "Gvarv" / "forecast_hour_by_hour.xml" url("http://sporing.posten.no/sporing.html") <<? Map("q" -> "123123123")
val http = new Http val request = url("http://scala-lang.org") http(request >>> System.out) // til OutputStream http(request as_str) // som string http(request <> ((xml:Elem) => xml \ "foo" \ "bar") // håndtert som xml import tagsoup.TagSoupHttp._ http(request </> ((xml:NodeSeq) => xml \\ "body" \ "@href") // vasket html og håndtert som xml
import xml._ import dispatch._ val http = new Http def parse(xml:Elem) = for { consignment <- xml \ "Consignment" totalweight <- consignment \ "TotalWeight" } yield totalweight.text http(url("http://beta.bring.no/sporing/sporing.xml") <<? Map("q" -> "TESTPACKAGE-AT-PICKUPPOINT") <> parse) <ConsignmentSet xmlns="http://www.bring.no/sporing/1.0"> <Consignment consignmentId="SHIPMENTNUMBER"> <TotalWeight unitCode="kg">16.5</TotalWeight> .. // List(16,5)
https://github.com/arktekk/scala-kurs-oppgaver/tree/master/music
for { a <- List(1, 2) b <- List(3, 4) } println(a + b) List(1, 2).foreach { a => List(3, 4).foreach { b => println(a + b) } }
for { a <- List(1, 2) } yield a + 1 List(1, 2).map(a => a + 1)
for { a <- List(1, 2) b <- List(3, 4) c <- List(5, 6) } yield a + b + c List(1, 2).flatMap { a => List(3, 4).flatMap { b => List(5, 6).map { c => a + b + c } } }
for { a <- List(1, 2) b <- List(3, 4) if a + b < 5 } yield a * b List(1, 2).flatMap { a => List(3, 4).withFilter { b => a + b < 5 }.map{ b => a * b } }
val R = "\\d+".r for { R(a) <- List("123", "abc", "321") } yield a List("123", "abc", "321").withFilter { case R(a) => true case _ => false }.map{ case R(a) => a }
for { a <- List(1, 2) b = a + 1 c <- List(3, 4) } yield a + b + c List(1, 2).map { a => val b = a + 1 (a, b) }.flatMap { case (a, b) => List(3, 4).map { c => a + b + c } }
Thou shalt only use implicit conversions for one of two (2) reasons:
Pimping members onto an existing type "Fixing" a broken type hierarchyclass StringOps(s:String){ def toInt = java.lang.Integer.parseInt(s) } implicit def augmentString(s:String):StringOps = new StringOps(s) val i = "543".toInt // augmentString("543").toInt
implicit class StringOps(s:String){ def toInt = java.lang.Integer.parseInt(s) }
type List[+A] = collection.immutable.List[A] type Pair[+A, +B] = Tuple2[A, B] implicit def augmentString(s:String):StringOps = new StringOps(s) final class ArrowAssoc[A](val x: A) { @inline def -> [B](y: B): Tuple2[A, B] = Tuple2(x, y) } implicit def any2ArrowAssoc[A](x: A) = new ArrowAssoc(x)
inspiser implicits i scope med REPL
> :implicits > :implicits -v
object Runnables { implicit def function2Runnable(f:() => Unit) = new Runnable{ def run() { f() } } } import Runnables._ SwingUtilities.invokeLater(() => println("Too convenient ?"))
implicit conversions mellom scala og java collections
import collection.JavaConversions._ val list:java.util.List[String] = Seq("hello", "world") val seq:Seq[String] = list
asScala og asJava metoder på java og scala collections
import collection.JavaConverters._ val list:java.util.List[String] = Seq("Hello", "World").asJava val seq:Seq[String] = list.asScala
implicit val msg = "Hello" def sayHello(s:String)(implicit m:String) = m + " " + s sayHello("World") > Hello World
gir deg tilgang til implicit parameters
val ordering = implicitly[Ordering[Int]] ordering.compare(1, 2) > -1
// implementasjon def implicitly[A](implicit a:A):A = a
object Min { def min[A <% Ordered[A]](a1:A, a2:A) = if(a1 < a2) a1 else a2 // sukker for def min[A](a1:A, a2:A)(implicit ev:A => Ordered[A]) = ... } case class Num(i:Int) Min.min(Num(1), Num(2))
No implicit view available from MinRun.Num => Ordered[MinRun.Num]. [error] Min.min(Num(1), Num(2)) [error] ^
object Min { def min[A : Ordering](a1:A, a2:A) = if(implicitly[Ordering[A]].lt(a1, a2)) a1 else a2 // sukker for def min[A](a1:A, a2:A)(implicit ev:Ordering[A]) = ... } Min.min(Num(1), Num(2)) // veldig fin for å kalle videre.. def min2[A : Ordering](a1:A, a2:A) = Min.min(a1, a2)
class Foo[A](a:A){ def int(implicit ev:A =:= Int):Int = a } new Foo(0).int new Foo("Hello").int // error: Cannot prove that java.lang.String =:= Int
def newInstance[A](implicit c:reflect.ClassTag[A]):A = manifest.runtimeClass.asInstanceOf[Class[A]].newInstance newInstance[java.util.ArrayList[String]] object Array { def apply(elms:A*)[A : ClassManifest]:Array[A] = ... } def create[A](a:A) = Array(a) // kompilerer ikke def create[A : ClassTag](a:A) = Array(a) // ok
trait Msg[A]{ def msg(a:A) } object MittApi { def needsMsg[A : Msg](a:A){ ... } } // brukers kode MittApi.needsMsg("Hello") /* could not find implicit value for evidence parameter of type implicitstuff.Msg[java.lang.String] MittApi.needsMsg("Hello") ^ */
import annotation.implicitNotFound @implicitNotFound("Du må definere/importere en implicit instans av Msg[${A}]") trait Msg[A]{ def msg(a:A) } object MittApi { def needsMsg[A : Msg](a:A){ ... } } // brukers kode MittApi.needsMsg("Hello") /* Du må definere/importere en implicit instans av Msg[java.lang.String] MittApi.needsMsg("Hello") ^ */
implicit object IntComparator extends java.util.Comparator[Int]{ def compare(a:Int, b:Int) = a - b } def myCompare[T](a:T, b:T)(implicit comarator:java.util.Comparator[Int]) = comparator.compare(a, b) myCompare(1,2) myCompare("Hello", "World") // error: could not find implicit value for evidence parameter // of type java.util.Comparator[java.lang.String]
implicit class Syntax[A](a:A){ def === (other:A)(implicit c:java.util.Comparator[A]) = c.compare(a, other) == 0 } 5 === 4
public int f(List<List<Integer>> l){ if(l != null){ if(l.size() >= 1){ List<Integer> l2 = l.get(0); if(l2 != null && l2.size() >= 1){ Integer i = l2.get(0); if(i == 1 || i == 2 || i == 3) return i; } } if(l.size() >= 2){ List<Integer> l2 = l.get(1); if(l2 != null && l2.size() >= 2) return l2.get(1); } } return 0; }
def f(l:List[List[Int]]) = l match { case List(List(x @ (1 | 2 | 3), _*), _*) => x case List(_, List(_, x, _*),_*) => x case _ => 0 }
x match { case _ => }
x match { case y => }
x match { case _:Foo => case a:C => case b:p.C => case c:T#C => case d:Singleton.type => case e:(A with B with C) => }
x match { case y @ _ => }
x match { case "hello" => case 5 => case true => case 'A' => case 5.5 => }
(x: @switch) match { case 1 => case 2 => case 3 => }
(x: @switch) match { case 1 => case 2 => case "3" => } // error: could not emit switch for @switch annotated match
val hello = "hello" "world" match { case hello => // matcher }
val Hello = "hello" "world" match { case Hello => // matcher ikke }
def f(x:Int, y:Int) = x match { case `y` => }
case class Foo(a:String, b:Int) x match { case Foo(aString, anInt) => }
case class Foo(a:String, b:Int) x match { case Foo("Hello", 5) => case Foo(aString, anInt) => }
sealed trait Tree case class Branch(l:Tree, r:Tree) extends Tree case class Leaf(v:Int) extends Tree def sum(t:Tree):Int = t match { case Branch(l, r) => sum(l) + sum(r) case Leaf(v) => v } val tree = Branch( Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4))) sum(tree)
x match { case (first, second) => }
x match { case (first, second, third) => }
x match { case List(a, b) => case List(a, b, c, _*) => }
x match { case List(a, b) => case List(a, b, c, d @ _*) => }
def unapply(a:A):Boolean def unapply(a:A):Option[B] def unapplySeq(a:A):Option[Seq[B]]
object Empty { def unapply(a:String):Boolean = a.trim.size == 0 } x match { case Empty() => }
object Even { def unapply(a:Int):Option[Int] = if(a % 2 == 0) Some(a) else None } x match { case Even(even) => }
class Name{ String first; String last; public Name(first:String, last:String){ this.first = first; this.last = last; } }
object FirstLast { def unapply(name:Name):Option[(String, String)] = Some(name.first, name.last) } (new Name("scala", "kurs")) match { case FirstLast(first, last) => }
object Csv { def unapplySeq(s:String) = Some(s.split(",").toSeq) } "1,2,3" match { case Csv(a, b, c) => a+"-"+b+"-"+c }
sealed trait Tree object Branch { private class Impl(val l:Tree, r:Tree) extends Tree def apply(l:Tree, r:Tree):Tree = new Impl(l, r) def unapply(t:Tree) = t match { case i:Impl => Some(i.l, i.r) case _ => None } } object Leaf { private class Impl(val v:Int) extends Tree def apply(v:Int):Tree = new Impl(v) def unapply(t:Tree) = t match { case i:Impl => Some(i.v) case _ => None } }
def sum(tree:Tree):Int = tree match { case Branch(left, right) => sum(left) + sum(right) case Leaf(value) => value }
case class XX(a:String, b:Int) x match { case a XX b => }
case class ::[A](head:A, tail:List[A]) extends List[A] { def ::[B >: A](b:B):List[B] = ::(b, this) } (1 :: 2 :: 3 :: Nil) match { case a :: b :: c :: Nil => }
case class ::[A](head:A, tail:List[A]) extends List[A] { def ::[B >: A](b:B):List[B] = ::(b, this) } (1 :: 2 :: 3 :: Nil) match { case ::(1, ::(2, ::(3, Nil))) => }
object -> { def unapply[A, B](ab:(A, B)):Option[(A, B)] = Some(ab) } (1 -> 2) match { case a -> b => } (1 -> 2 -> 3) match { case a -> b -> c => }
case class EX(l:List[String], num:Int, s:String) x match { case l EX (num, s) => }
case class EX(l:List[String], num:Int, s:String) x match { case a :: b :: c EX (num, s) => }
x match { case 1 | 2 => case _:Foo | _:Bar => }
try { // throw something } catch { case e @ (_:ExA | _:ExB) => // multicatch }
<foo>bar</foo> match { case <foo>{what}</foo> => }
x match { case y if y > 2 => }
val pos:PartialFunction[Int, String] = { case n if n > 0 => n.toString } pos.isDefinedAt(5) // true pos.isDefinedAt(-1) // false pos(5) // "5" pos(-1) // java.util.NoSuchElementException
val pos:PartialFunction[Int, String] = { case n if n > 0 => n.toString } val notPos:PartialFunction[Int, String] = { case n if n <= 0 => "Not positive" } val all = pos orElse notPos for(i <- -5 to 5) println(all(i))
val Num = "(\\d+)".r List("123", "abc", "321").collect{ case Num(num) => num.toInt } // List(123, 321)
List(-2, -1, 0, 1, 2).foldLeft(0){ case (a, e) => if e < 0 => a case (a, e) => a + e }
val (minors, adults) = people.partition(_.age < 18) val Email = "(.+)@(.+)".r val EMail(name, domain) = "foo@bar.com"
object Even { def unapply(i:Int) = if(i % 2 == 0) Some(i) else None } for{ Even(number) <- List(1, 2, 3, 4) } yield number
val list:List[Any] = List(1, 2, 3) list match { case x:List[String] => "Strings" // matcher case x:List[Int] => "Ints" }
val a:Option[Int] = ... a match { case Some(i) => Some(i * 2) case _ => None }
val a:Option[Int] = ... a.map(i => i * 2)
val a:Option[String] = ... val b:Option[String] = ... (a, b) match { case (Some(hello), Some(world)) => Some(hello + " " + world) case _ => None }
val a:Option[String] = ... val b:Option[String] = ... for{ hello <- a world <- b } yield hello + " " + world
Skriv ditt eget webrammeverk! (thats right)
Within the type system of a programming language, covariance and contravariance refers to the ordering of types from narrower to wider and their interchangeability or equivalence in certain situations (such as parameters, generics, and return types).
alle typer er
type X[T] // T er invariant
X[A] kan benyttes for X[B] hvis A == B
type X[+T] // + betyr at T er covariant
X[A] kan benyttes for X[B] hvis A er subtype av B
type X[-T] // - betyr at T er contravariant
X[A] kan benyttes for X[B] hvis A er supertype av B
class SuperType class TheType extends SuperType class SubType extends TheType def x(theType:TheType){ ... } x(new SuperType) // ikke ok x(new TheType) x(new SubType) // ok
class Invariant[A](a:A){ def get:A = a def set(a:A){ ... } } def in(invariant:Invariant[TheType]){ ... } in(new Invariant[SuperType]) // ikke ok in(new Invariant[TheType]) in(new Invariant[SubType]) // ikke ok
class Covariant[+A](a:A){ def get:A = a def set(a:A){ ... } // ikke ok, contravariant position } def co(covariant:Covariant[TheType]){ ... } co(new Covariant[SuperType]) // ikke ok co(new Covariant[TheType]) co(new Covariant[SubType]) // ok
class Contravariant[-A](a:A){ def get:A = a // ikke ok, covariant position def set(a:A){ ... } } def contra(contravariant:Contravariant[TheType]){ ... } contra(new Contravariant[SuperType]) // ok contra(new Contravariant[TheType]) contra(new Contravariant[SubType]) // ikke ok
A <: B // A subtype av B
class Foo class Bar extends Foo class Foos[F <: Foo](var init:F){ def set(f:F){ init = f } def get = init } val bars = new Foos[Bar](new Bar) bars.set(new Bar) val f:Bar = bars.get // found Foo, required Bar bars.set(new Foo) // type arguments [String] do not conform to class // Foos's type parameter bounds [F <: Foo] val strings = new Foos[String]("")
A >: B // A supertype av B
class Foo class Bar extends Foo class Generator[F >: Bar]{ def next:F = new Bar } val gen = new Generator[Foo] val foo:Foo = gen.next
sealed trait Lst[A] case object Empty extends Lst[Nothing] case class Cons[A](head:A, tail:Lst[A]) extends Lst[A] Cons("Hello", Empty)
sealed trait Lst[A] case object Empty extends Lst[Nothing] case class Cons[A](head:A, tail:Lst[A]) extends Lst[A] Cons("Hello", Empty)
// found : Empty.type (with underlying type object Empty) // required: Lst[java.lang.String] // Note: Nothing <: java.lang.String (and Empty.type <: Lst[Nothing]), // but trait Lst is invariant in type A. // You may wish to define A as +A instead. (SLS 4.5) // Cons("Hello", Empty)
sealed trait Lst[+A] // ok, fixed it case object Empty extends Lst[Nothing] case class Cons[A](head:A, tail:Lst[A]) extends Lst[A] Cons("Hello", Empty)
sealed trait Lst[+A]{ def ::(a:A):Lst[A] = Cons(a, this) } case object Empty extends Lst[Nothing] case class Cons[A](head:A, tail:Lst[A]) extends Lst[A] // i bruk "Hello" :: Empty
sealed trait Lst[+A]{ def ::(a:A):Lst[A] = Cons(a, this) } case object Empty extends Lst[Nothing] case class Cons[A](head:A, tail:Lst[A]) extends Lst[A] /* covariant type A occurs in contravariant position in type A of value a def ::(a:A):Lst[A] = Cons(a, this) ^ */
sealed trait Lst[+A]{ def ::[B >: A](b:B):Lst[B] = Cons(b, this) // ok, fixed it } case object Empty extends Lst[Nothing] case class Cons[A](head:A, tail:Lst[A]) extends Lst[A] val lst:Lst[String] = "Hello" :: Empty val lst2:Lst[Any] = 1 :: "Hello" :: Empty
<?xml version="1.0" encoding="utf-8"?> <weatherdata> <forecast> <text> <location> <time from="2011-12-23" to="2011-12-24" type="obsforecast"> <title>Friday and Saturday</title> <body><strong>Telemark:</strong> Våte veibaner og synkende temperatur kan stedvis gi glattere veier fra natt til julaften.</body> </time> <time from="2011-12-24" to="2011-12-25"> <title>Saturday and Sunday</title> <body><strong>Østlandet og Telemark:</strong> Vestlig bris. Stort sett pent vær. I kveld sørvestlig bris, økende til liten og periodevis stiv kuling 15 m/s på kysten. Skyet eller delvis skyet. Oppholdsvær, men lengst vest regn, snø i høyden. Søndag kveld sørvestlig frisk bris 10, sterk kuling 20 på kysten. Spredt regn, snø i høyden. Nedbør vesentlig i vestlige områder.</body> </time> ...
case class Time(from:String, to:String, title:String, body:String) val xml = XML.load(getClass.getResourceAsStream("forecast_hour_by_hour.xml")) val forecasts = for { forecast <- xml \ "forecast" text = forecast \ "text" // child select time <- text \\ "time" // deep select from = time \ "@from" // attribute select to = time \ "@to" title = time \ "title" body = time \ "body" } yield Time(from.text, to.text, title.text, body.text)
<weatherdata> <forecast> <text> <location>{ forecasts.flatMap{ case Time(from, to, title, body) => <time from={from} to={to}> <title>{title}</title> <body>{body}</body> </time> }} </location> </text> </forecast> </weatherdata>
val obs = for { time <- xml \\ "time" tpe = time \ "@type" if tpe.text == "obsforecast" body = time \ "body" title = time \ "title" } yield title.text -> body.text // (Friday and Saturday,<strong>Telemark:</strong> Våte veibaner og // synkende temperatur kan stedvis gi glattere veier fra natt til julaften.)
GET / HTTP/1.1 User-Agent: curl/7.19.7 Host: localhost:8080 Accept: */* HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 357 Server: Jetty(7.6.0.v20120127)
class Example extends Plan { def intent = { case GET(Path("/")) => OK ~> Html5(<html>...</html>) } }
// sync type Intent[-A,-B] = PartialFunction[HttpRequest[A], ResponseFunction[B]] //async type Intent[-A,-B] = PartialFunction[HttpRequest[A] with Responder[B], Any] trait Responder[+R] { def respond(rf: unfiltered.response.ResponseFunction[R]) }
trait Plan extends Filter { def intent:Intent[HttpServletRequest, HttpServletResponse] def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) = ... }
object Path { def unapply[T](req: HttpRequest[T]) = Some(req.uri.split('?')(0)) } object Seg { def unapply(path: String): Option[List[String]] = path.split("/").toList match { case "" :: rest => Some(rest) // skip a leading slash case all => Some(all) } }
GET /item/5 HTTP/1.1 User-Agent: curl/7.19.7 Host: localhost:8080 Accept: */*
def intent = { case Path(Seg(List("item", number))) => // number == "5" Ok ~> Html5(...) case Path(Seg(List("you", can, "have", many))) => Ok ~> Html5(...) }
GET /item?filter=foo&filter=bar&monkey=donkey HTTP/1.1 User-Agent: curl/7.19.7 Host: localhost:8080 Accept: */* `
def intent = { case Path("/item") & QueryParams(q) => val filter = q("filter") // Seq("foo", "bar") val monkey = q("monkey") // Seq("donkey") val nope = q("nope") // Seq() Ok ~> Html5(...) }
def intent = { case Path("/") => ServiceUnavailable ~> TextXmlContent ~> ResponseString("<error>not available</error>) }
HTTP/1.1 503 Service Unavailable Content-Type: text/xml; charset=utf-8 Content-Length: 28 Server: Jetty(7.6.0.v20120127) <error>not available</error>
unfiltered.jetty.Http.local(8080).filter(new Example).run()
object Coffees extends Table[(String, Int, Double)]("COFFEES") { def name = column[String]("COF_NAME", O.PrimaryKey) def supID = column[Int]("SUP_ID") def price = column[Double]("PRICE") def * = name ~ supID ~ price } Coffees.insertAll( ("Colombian", 101, 7.99), ("Colombian_Decaf", 101, 8.99), ("French_Roast_Decaf", 49, 9.99)) val q = for { c <- Coffees if c.supID === 101 } yield (c.name, c.price)
case class Coffee(name: String, supID: Int, price: Double) implicit val getCoffeeResult = GetResult(r => Coffee(r.<<, r.<<, r.<<)) Database.forURL("...") withSession { Seq( Coffee("Colombian", 101, 7.99), Coffee("Colombian_Decaf", 101, 8.99), Coffee("French_Roast_Decaf", 49, 9.99) ).foreach(c => sqlu""" insert into coffees values (${c.name}, ${c.supID}, ${c.price}) """).execute) val sup = 101 val q = sql"select * from coffees where sup_id = $sup".as[Coffee] // A bind variable to prevent SQL injection ^ q.foreach(println) }
val q = sql("select name, age from person") val r:List[Int] = q() map (_ get "age") // List(36, 14) q() map (_ get "salary") // error: No field String("salary") in record
val q = sql("select name, age from person where age > ?") q("30") map (_ get "name") // error: type mismatch; // found : String("30") // required: Int q(30) map (_ get "name") // ok
sealed abstract class JValue case object JNothing extends JValue // 'zero' for JValue case object JNull extends JValue case class JString(s: String) extends JValue case class JDouble(num: Double) extends JValue case class JDecimal(num: BigDecimal) extends JValue case class JInt(num: BigInt) extends JValue case class JBool(value: Boolean) extends JValue case class JObject(obj: List[JField]) extends JValue case class JArray(arr: List[JValue]) extends JValue type JField = (String, JValue)
import org.json4s._ import org.json4s.native.JsonMethods._ parse(""" { "numbers" : [1, 2, 3, 4] } """) // JObject(List((numbers,JArray(List(JInt(1), JInt(2), JInt(3), JInt(4))))))
import argonaut._, Argonaut._ case class Person(name: String, age: Int, things: List[String]) implicit def PersonCodecJson = casecodec3(Person.apply, Person.unapply)("name", "age", "things") val person = Person("Bam Bam", 2, List("club")) val json: Json = person.asJson val prettyprinted: String = json.spaces2 val parsed: Option[Person] = prettyprinted.decodeOption[Person]
{ "groups": [ { "groupName": "The Beatles", "members": [ { "name": "John Lennon", "born": 1940 }, { "name": "Paul McCartney", "born": 1942 }, { "name": "Ringo Starr", "born": 1940 }, { "name": "George Harrison", "born": 1943 } ] } ] }
import rapture._ import core._, io._, net._, uri._, json._, codec._ // Read a file into a string import encodings.`UTF-8` val src = uri"http://rapture.io/sample.json".slurp[Char] // Parse it as Json import jsonBackends.jackson._ val json = Json.parse(src) // Auto-extract a `Group` into a case class structure case class Member(name: String, born: Int) case class Group(groupName: String, members: Set[Member]) json.groups(0).as[Group]
import dispatch._, Defaults._ val svc = url("http://api.hostip.info/country.php") val country = Http(svc OK as.String) // non blocking foreach for (c <- country) println(c) // blocking! val c = country() // map, flatMap etc. (non-blocking) val length = for (c <- country) yield c.length
// legg til form-parameter def myPostWithParams = myPost.addParameter("key", "value") // POST + legg til form-parameter def myPostWithParams = myRequest << Map("key" -> "value") // POST body def myPostWithBody = myRequest << """{"key": "value"}""" // legg til query param def myRequestWithParams = myRequest.addQueryParameter("key", "value") // legg til query param def myRequestWithParams = myRequest <<? Map("key" -> "value") // PUT java.io.File def myPut = myRequest <<< myFile
Http(request OK as.String) //200 range, eller Failure Http(request > as.String) //aksepterer alle def f(r:Response) = ... Http(request > f) //bruk min egen funksjon
Future[A] er en representasjon av en verdi A som kan bli tilgjengelig på et eller annet tidspunkt
Future kan være i 2 tilstander
En ferdig future er enten 'successful' eller 'failed'
Mye brukt for asynkron / concurrent / parallell kode
Alle computations kjøres på en ExecutionContext
import scala.concurrent._ import ExecutionContext.Implicits.global val work:Future[Result] = Future { ... // do heavy work returning Result }
import scala.util.{Success, Failure} work.onComplete{ case Success(result) => .. case Failure(ex) => ... } work.onSuccess{ case result => ... } work.onFailure{ case ex:Exception => ... }
map, flatMap, filter, forEach og mye annet
val fa:Future[Int] = ... def fb(a:A):Future[String] = ... val x:Future[String] = for { a <- fa b <- fb(a) if a > 10 } yield b
val ok = Future{ 2 / 0 } recover { case x:ArithmeticException => 0 } for(r <- ok) println(r) // 0
val fa:Future[A] = ... val fb:Future[B] = ... val fab:Future[(A, B)] = fa zip fb
val listOfFuture:List[Future[Int]] = ... val futureOfList:Future[List[Int]] = Future.sequence(listOfFuture)
val p = Promise[Int] val f = p.future f.foreach(i => println(i)) // på et eller annet tidspunkt p.success(5)
import scala.concurrent.duration._ val f:Future[Int] = ... val i:Int = Await.result(f, 5.seconds)
Akka is a toolkit and runtime for building highly concurrent, distributed, and fault tolerant event-driven applications on the JVM.
Actors er concurrent prosesser som kommuniserer via meldinger
import akka.actors._ case class Message(msg:String) val system = ActorSystem() // ActorRef er en nettverkstransparent referanse til en actor val client:ActorRef = system.actorOf(Props[Client]) // ! sender melding til en actor client ! Message("hi") class Client extends Actor { // implementer all message handling i receive m/pattern matching def receive = { case Message(msg) => println(s"got $msg") } }
50 million msg/sec on a single machine. Small memory footprint; ~2.5 million actors per GB of heap.
// instansier system.actorOf(Props[SomeActor], name = "some-actor") system.actorOf(Props(new SomeActor)) // lookup system.actorSelection("/user/some-actor")
class Supervisor extends Actor { override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 minute) { case _: ArithmeticException ⇒ Resume case _: NullPointerException ⇒ Restart case _: Exception ⇒ Escalate } val worker = context.actorOf(Props[Worker]) def receive = { case n: Int => worker forward n } }