# HG changeset patch # User Christian Urban # Date 1606707210 0 # Node ID d19b0a50ceb9467ffec04b072f601d9247268124 # Parent 5616b45d656fed3ef4709b4b94e96687b4d1e78c updated diff -r 5616b45d656f -r d19b0a50ceb9 progs/lecture4.scala --- a/progs/lecture4.scala Mon Nov 30 00:06:15 2020 +0000 +++ b/progs/lecture4.scala Mon Nov 30 03:33:30 2020 +0000 @@ -88,6 +88,165 @@ comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil) +// Polymorphic Types +//=================== + +// You do not want to write functions like contains, first, +// length and so on for every type of lists. + +def length_int_list(lst: List[Int]): Int = lst match { + case Nil => 0 + case x::xs => 1 + length_int_list(xs) +} + +length_int_list(List(1, 2, 3, 4)) + +def length_string_list(lst: List[String]): Int = lst match { + case Nil => 0 + case _::xs => 1 + length_string_list(xs) +} + +length_string_list(List("1", "2", "3", "4")) + + +// you can make the function parametric in type(s) + +def length[A](lst: List[A]): Int = lst match { + case Nil => 0 + case x::xs => 1 + length(xs) +} +length(List("1", "2", "3", "4")) +length(List(1, 2, 3, 4)) + +length[Int](List(1, 2, 3, 4)) + + +def map[A, B](lst: List[A], f: A => B): List[B] = lst match { + case Nil => Nil + case x::xs => f(x)::map(xs, f) +} + +map(List(1, 2, 3, 4), (x: Int) => x.toString) + + +// from knight1.scala +def first(xs: List[Pos], f: Pos => Option[Path]) : Option[Path] = ??? + +// should be +def first[A, B](xs: List[A], f: A => Option[B]) : Option[B] = ??? + +// Type inference is local in Scala + +def id[T](x: T) : T = x + +val x = id(322) // Int +val y = id("hey") // String +val z = id(Set(1,2,3,4)) // Set[Int] + + +// The type variable concept in Scala can get really complicated. +// +// - variance (OO) +// - bounds (subtyping) +// - quantification + +// Java has issues with this too: Java allows +// to write the following incorrect code, and +// only recovers by raising an exception +// at runtime. + +// Object[] arr = new Integer[10]; +// arr[0] = "Hello World"; + + +// Scala gives you a compile-time error, which +// is much better. + +var arr = Array[Int]() +arr(0) = "Hello World" + + + + +// Function definitions again +//============================ + +// variable arguments + +def printAll(strings: String*) = { + strings.foreach(println) +} + +printAll() +printAll("foo") +printAll("foo", "bar") +printAll("foo", "bar", "baz") + +// pass a list to the varargs field +val fruits = List("apple", "banana", "cherry") + +printAll(fruits: _*) + + +// you can also implement your own string interpolations +import scala.language.implicitConversions +import scala.language.reflectiveCalls + +implicit def sring_inters(sc: StringContext) = new { + def i(args: Any*): String = s"${sc.s(args:_*)}\n" +} + +i"add ${3+2} ${3 * 3}" + + +// default arguments + +def length[A](xs: List[A]) : Int = xs match { + case Nil => 0 + case _ :: tail => 1 + length(tail) +} + +def lengthT[A](xs: List[A], acc : Int = 0) : Int = xs match { + case Nil => acc + case _ :: tail => lengthT(tail, 1 + acc) +} + +lengthT(List.fill(100000)(1)) + + +def fact(n: BigInt, acc: BigInt = 1): BigInt = + if (n == 0) acc else fact(n - 1, n * acc) + +fact(10) + + + +// currying (Haskell Curry) + +def add(x: Int, y: Int) = x + y + +List(1,2,3,4,5).map(x => add(3, x)) + +def add2(x: Int)(y: Int) = x + y + +List(1,2,3,4,5).map(add2(3)) + +val a3 : Int => Int = add2(3) + +// currying helps sometimes with type inference + +def find[A](xs: List[A])(pred: A => Boolean): Option[A] = { + xs match { + case Nil => None + case hd :: tl => + if (pred(hd)) Some(hd) else find(tl)(pred) + } +} + +find(List(1, 2, 3))(x => x % 2 == 0) + +// Source.fromURL(url)(encoding) +// Source.fromFile(name)(encoding) // Sudoku diff -r 5616b45d656f -r d19b0a50ceb9 progs/lecture5.scala --- a/progs/lecture5.scala Mon Nov 30 00:06:15 2020 +0000 +++ b/progs/lecture5.scala Mon Nov 30 03:33:30 2020 +0000 @@ -172,105 +172,6 @@ -// Polymorphic Types -//=================== - -// You do not want to write functions like contains, first, -// length and so on for every type of lists. - - -def length_string_list(lst: List[String]): Int = lst match { - case Nil => 0 - case _::xs => 1 + length_string_list(xs) -} - -def length_int_list(lst: List[Int]): Int = lst match { - case Nil => 0 - case x::xs => 1 + length_int_list(xs) -} - -length_string_list(List("1", "2", "3", "4")) -length_string_list(List(1, 2, 3, 4)) - -// you can make the function parametric in type(s) - -def length[A](lst: List[A]): Int = lst match { - case Nil => 0 - case x::xs => 1 + length(xs) -} -length[String](List("1", "2", "3", "4")) -length(List(1, 2, 3, 4)) - - -def map[A, B](lst: List[A], f: A => B): List[B] = lst match { - case Nil => Nil - case x::xs => f(x)::map(xs, f) -} - -map(List(1, 2, 3, 4), (x: Int) => x.toString) - - - -// distinct / distinctBy - -val ls = List(1,2,3,3,2,4,3,2,1) -ls.distinct - -// .minBy(_._2) -// .sortBy(_._1) - -def distinctBy[B, C](xs: List[B], - f: B => C, - acc: List[C] = Nil): List[B] = xs match { - case Nil => Nil - case x::xs => { - val res = f(x) - if (acc.contains(res) distinctBy(xs, f, acc) - else x::distinctBy(xs, f, res::acc) - } -} - -val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd') - -distinctBy(cs, (c:Char) => c.toUpper) - -// since 2.13 - -cs.distinctBy((c:Char) => c.toUpper) - - -// Type inference is local in Scala - -def id[T](x: T) : T = x - -val x = id(322) // Int -val y = id("hey") // String -val z = id(Set(1,2,3,4)) // Set[Int] - -id[+A, -B] - -// The type variable concept in Scala can get really complicated. -// -// - variance (OO) -// - bounds (subtyping) -// - quantification - -// Java has issues with this too: Java allows -// to write the following incorrect code, and -// only recovers by raising an exception -// at runtime. - -// Object[] arr = new Integer[10]; -// arr[0] = "Hello World"; - - -// Scala gives you a compile-time error, which -// is much better. - -var arr = Array[Int]() -arr(0) = "Hello World" - - // (Immutable) // Object Oriented Programming in Scala //