progs/lecture4.scala
author Christian Urban <urbanc@in.tum.de>
Tue, 26 Nov 2019 01:22:36 +0000
changeset 325 ca9c1cf929fa
parent 320 cdfb2ce30a3d
child 326 e5453add7df6
permissions -rw-r--r--
updated
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
     1
// Scala Lecture 4
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
     2
//=================
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
     3
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
     4
325
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
     5
// expressions (essentially trees)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
     6
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
     7
abstract class Exp
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
     8
case class N(n: Int) extends Exp                  // for numbers
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
     9
case class Plus(e1: Exp, e2: Exp) extends Exp
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    10
case class Times(e1: Exp, e2: Exp) extends Exp
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    11
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    12
def string(e: Exp) : String = e match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    13
  case N(n) => s"$n"
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    14
  case Plus(e1, e2) => s"(${string(e1)} + ${string(e2)})" 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    15
  case Times(e1, e2) => s"(${string(e1)} * ${string(e2)})"
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    16
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    17
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    18
val e = Plus(N(9), Times(N(3), N(4)))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    19
println(string(e))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    20
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    21
def eval(e: Exp) : Int = e match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    22
  case N(n) => n
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    23
  case Plus(e1, e2) => eval(e1) + eval(e2) 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    24
  case Times(e1, e2) => eval(e1) * eval(e2) 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    25
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    26
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    27
println(eval(e))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    28
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    29
// simplification rules:
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    30
// e + 0, 0 + e => e 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    31
// e * 0, 0 * e => 0
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    32
// e * 1, 1 * e => e
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    33
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    34
def simp(e: Exp) : Exp = e match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    35
  case N(n) => N(n)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    36
  case Plus(e1, e2) => (simp(e1), simp(e2)) match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    37
    case (N(0), e2s) => e2s
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    38
    case (e1s, N(0)) => e1s
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    39
    case (e1s, e2s) => Plus(e1s, e2s)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    40
  }  
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    41
  case Times(e1, e2) => (simp(e1), simp(e2)) match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    42
    case (N(0), _) => N(0)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    43
    case (_, N(0)) => N(0)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    44
    case (N(1), e2s) => e2s
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    45
    case (e1s, N(1)) => e1s
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    46
    case (e1s, e2s) => Times(e1s, e2s)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    47
  }  
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    48
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    49
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    50
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    51
val e2 = Times(Plus(N(0), N(1)), Plus(N(0), N(9)))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    52
println(string(e2))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    53
println(string(simp(e2)))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    54
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    55
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    56
// Tokens and Reverse Polish Notation
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    57
abstract class Token
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    58
case class T(n: Int) extends Token
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    59
case object PL extends Token
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    60
case object TI extends Token
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    61
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    62
// transfroming an Exp into a list of tokens
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    63
def rp(e: Exp) : List[Token] = e match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    64
  case N(n) => List(T(n))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    65
  case Plus(e1, e2) => rp(e1) ::: rp(e2) ::: List(PL) 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    66
  case Times(e1, e2) => rp(e1) ::: rp(e2) ::: List(TI) 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    67
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    68
println(string(e2))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    69
println(rp(e2))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    70
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    71
def comp(ls: List[Token], st: List[Int]) : Int = (ls, st) match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    72
  case (Nil, st) => st.head 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    73
  case (T(n)::rest, st) => comp(rest, n::st)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    74
  case (PL::rest, n1::n2::st) => comp(rest, n1 + n2::st)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    75
  case (TI::rest, n1::n2::st) => comp(rest, n1 * n2::st)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    76
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    77
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    78
comp(rp(e), Nil)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    79
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    80
def proc(s: String) : Token = s match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    81
  case  "+" => PL
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    82
  case  "*" => TI
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    83
  case  _ => T(s.toInt) 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    84
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    85
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    86
comp("1 2 + 4 * 5 + 3 +".split(" ").toList.map(proc), Nil)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    87
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    88
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    89
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    90
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    91
// Sudoku 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    92
//========
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    93
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    94
// THE POINT OF THIS CODE IS NOT TO BE SUPER
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    95
// EFFICIENT AND FAST, just explaining exhaustive
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    96
// depth-first search
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    97
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    98
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
    99
val game0 = """.14.6.3..
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   100
              |62...4..9
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   101
              |.8..5.6..
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   102
              |.6.2....3
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   103
              |.7..1..5.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   104
              |5....9.6.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   105
              |..6.2..3.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   106
              |1..5...92
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   107
              |..7.9.41.""".stripMargin.replaceAll("\\n", "")
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   108
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   109
type Pos = (Int, Int)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   110
val EmptyValue = '.'
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   111
val MaxValue = 9
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   112
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   113
val allValues = "123456789".toList
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   114
val indexes = (0 to 8).toList
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   115
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   116
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   117
def empty(game: String) = game.indexOf(EmptyValue)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   118
def isDone(game: String) = empty(game) == -1 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   119
def emptyPosition(game: String) = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   120
  (empty(game) % MaxValue, empty(game) / MaxValue)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   121
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   122
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   123
def get_row(game: String, y: Int) = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   124
  indexes.map(col => game(y * MaxValue + col))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   125
def get_col(game: String, x: Int) = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   126
  indexes.map(row => game(x + row * MaxValue))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   127
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   128
def get_box(game: String, pos: Pos): List[Char] = {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   129
    def base(p: Int): Int = (p / 3) * 3
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   130
    val x0 = base(pos._1)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   131
    val y0 = base(pos._2)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   132
    val ys = (y0 until y0 + 3).toList
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   133
    (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   134
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   135
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   136
//get_row(game0, 0)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   137
//get_row(game0, 1)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   138
//get_col(game0, 0)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   139
//get_box(game0, (3, 1))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   140
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   141
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   142
// this is not mutable!!
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   143
def update(game: String, pos: Int, value: Char): String = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   144
  game.updated(pos, value)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   145
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   146
def toAvoid(game: String, pos: Pos): List[Char] = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   147
  (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   148
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   149
def candidates(game: String, pos: Pos): List[Char] = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   150
  allValues.diff(toAvoid(game, pos))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   151
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   152
//candidates(game0, (0,0))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   153
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   154
def pretty(game: String): String = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   155
  "\n" + (game.sliding(MaxValue, MaxValue).mkString("\n"))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   156
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   157
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   158
def search(game: String): List[String] = {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   159
  if (isDone(game)) List(game)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   160
  else {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   161
    val cs = candidates(game, emptyPosition(game))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   162
    cs.map(c => search(update(game, empty(game), c))).toList.flatten
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   163
  }
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   164
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   165
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   166
search(game0).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   167
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   168
val game1 = """23.915...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   169
              |...2..54.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   170
              |6.7......
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   171
              |..1.....9
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   172
              |89.5.3.17
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   173
              |5.....6..
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   174
              |......9.5
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   175
              |.16..7...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   176
              |...329..1""".stripMargin.replaceAll("\\n", "")
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   177
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   178
search(game1).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   179
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   180
// a game that is in the hard category
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   181
val game2 = """8........
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   182
              |..36.....
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   183
              |.7..9.2..
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   184
              |.5...7...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   185
              |....457..
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   186
              |...1...3.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   187
              |..1....68
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   188
              |..85...1.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   189
              |.9....4..""".stripMargin.replaceAll("\\n", "")
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   190
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   191
search(game2).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   192
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   193
// game with multiple solutions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   194
val game3 = """.8...9743
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   195
              |.5...8.1.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   196
              |.1.......
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   197
              |8....5...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   198
              |...8.4...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   199
              |...3....6
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   200
              |.......7.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   201
              |.3.5...8.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   202
              |9724...5.""".stripMargin.replaceAll("\\n", "")
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   203
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   204
search(game3).map(pretty).foreach(println)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   205
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   206
// for measuring time
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   207
def time_needed[T](i: Int, code: => T) = {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   208
  val start = System.nanoTime()
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   209
  for (j <- 1 to i) code
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   210
  val end = System.nanoTime()
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   211
  s"${(end - start) / 1.0e9} secs"
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   212
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   213
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   214
time_needed(1, search(game2))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   215
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   216
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   217
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   218
// Tail recursion
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   219
//================
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   220
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   221
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   222
def fact(n: Long): Long = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   223
  if (n == 0) 1 else n * fact(n - 1)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   224
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   225
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   226
fact(10)              // ok
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   227
fact(1000)            // silly
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   228
fact(10000)           // produces a stackoverflow
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   229
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   230
def factB(n: BigInt): BigInt = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   231
  if (n == 0) 1 else n * factB(n - 1)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   232
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   233
factB(1000)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   234
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   235
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   236
def factT(n: BigInt, acc: BigInt): BigInt =
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   237
  if (n == 0) acc else factT(n - 1, n * acc)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   238
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   239
factT(10, 1)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   240
println(factT(100000, 1))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   241
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   242
// there is a flag for ensuring a function is tail recursive
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   243
import scala.annotation.tailrec
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   244
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   245
@tailrec
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   246
def factT(n: BigInt, acc: BigInt): BigInt =
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   247
  if (n == 0) acc else factT(n - 1, n * acc)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   248
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   249
factT(100000, 1)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   250
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   251
// for tail-recursive functions the Scala compiler
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   252
// generates loop-like code, which does not need
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   253
// to allocate stack-space in each recursive
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   254
// call; Scala can do this only for tail-recursive
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   255
// functions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   256
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   257
// tail recursive version that searches 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   258
// for all Sudoku solutions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   259
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   260
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   261
def searchT(games: List[String], sols: List[String]): List[String] = games match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   262
  case Nil => sols
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   263
  case game::rest => {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   264
    if (isDone(game)) searchT(rest, game::sols)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   265
    else {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   266
      val cs = candidates(game, emptyPosition(game))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   267
      searchT(cs.map(c => update(game, empty(game), c)) ::: rest, sols)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   268
    }
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   269
  }
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   270
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   271
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   272
searchT(List(game3), List()).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   273
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   274
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   275
// tail recursive version that searches 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   276
// for a single solution
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   277
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   278
def search1T(games: List[String]): Option[String] = games match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   279
  case Nil => None
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   280
  case game::rest => {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   281
    if (isDone(game)) Some(game)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   282
    else {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   283
      val cs = candidates(game, emptyPosition(game))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   284
      search1T(cs.map(c => update(game, empty(game), c)) ::: rest)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   285
    }
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   286
  }
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   287
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   288
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   289
search1T(List(game3)).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   290
time_needed(1, search1T(List(game3)))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   291
time_needed(1, search1T(List(game2)))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   292
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   293
// game with multiple solutions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   294
val game3 = """.8...9743
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   295
              |.5...8.1.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   296
              |.1.......
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   297
              |8....5...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   298
              |...8.4...
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   299
              |...3....6
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   300
              |.......7.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   301
              |.3.5...8.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   302
              |9724...5.""".stripMargin.replaceAll("\\n", "")
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   303
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   304
searchT(List(game3), Nil).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   305
search1T(List(game3)).map(pretty)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   306
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   307
// Moral: Whenever a recursive function is resource-critical
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   308
// (i.e. works with large recursion depth), then you need to
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   309
// write it in tail-recursive fashion.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   310
// 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   311
// Unfortuantely, Scala because of current limitations in 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   312
// the JVM is not as clever as other functional languages. It can 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   313
// only optimise "self-tail calls". This excludes the cases of 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   314
// multiple functions making tail calls to each other. Well,
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   315
// nothing is perfect. 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   316
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   317
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   318
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   319
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   320
// Polymorphic Types
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   321
//===================
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   322
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   323
// You do not want to write functions like contains, first, 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   324
// length and so on for every type of lists.
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   325
224
42d760984496 updated
Christian Urban <urbanc@in.tum.de>
parents: 223
diff changeset
   326
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   327
def length_string_list(lst: List[String]): Int = lst match {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   328
  case Nil => 0
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   329
  case x::xs => 1 + length_string_list(xs)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   330
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   331
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   332
def length_int_list(lst: List[Int]): Int = lst match {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   333
  case Nil => 0
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   334
  case x::xs => 1 + length_int_list(xs)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   335
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   336
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   337
length_string_list(List("1", "2", "3", "4"))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   338
length_int_list(List(1, 2, 3, 4))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   339
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   340
def length[A](lst: List[A]): Int = lst match {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   341
  case Nil => 0
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   342
  case x::xs => 1 + length(xs)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   343
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   344
length(List("1", "2", "3", "4"))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   345
length(List(1, 2, 3, 4))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   346
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   347
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   348
def map[A, B](lst: List[A], f: A => B): List[B] = lst match {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   349
  case Nil => Nil
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   350
  case x::xs => f(x)::map(xs, f) 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   351
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   352
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   353
map(List(1, 2, 3, 4), (x: Int) => x.toString)
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   354
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   355
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   356
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   357
// distinct / distinctBy
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   358
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   359
val ls = List(1,2,3,3,2,4,3,2,1)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   360
ls.distinct
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   361
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   362
ls.minBy(_._2)
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   363
ls.sortBy(_._1)
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   364
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   365
def distinctBy[B, C](xs: List[B], 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   366
                     f: B => C, 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   367
                     acc: List[C] = Nil): List[B] = xs match {
218
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   368
  case Nil => Nil
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   369
  case x::xs => {
218
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   370
    val res = f(x)
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   371
    if (acc.contains(res)) distinctBy(xs, f, acc)  
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   372
    else x::distinctBy(xs, f, res::acc)
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   373
  }
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   374
} 
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   375
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   376
// distinctBy  with the identity function is 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   377
// just distinct
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   378
distinctBy(ls, (x: Int) => x)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   379
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   380
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   381
val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd')
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   382
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   383
distinctBy(cs, (c:Char) => c.toUpper)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   384
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   385
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   386
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   387
// Type inference is local in Scala
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   388
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   389
def id[T](x: T) : T = x
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   390
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   391
val x = id(322)          // Int
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   392
val y = id("hey")        // String
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   393
val z = id(Set[Int](1,2,3,4)) // Set[Int]
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   394
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   395
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   396
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   397
// The type variable concept in Scala can get really complicated.
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   398
//
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   399
// - variance (OO)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   400
// - bounds (subtyping)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   401
// - quantification
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   402
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   403
// Java has issues with this too: Java allows
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   404
// to write the following incorrect code, and
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   405
// only recovers by raising an exception
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   406
// at runtime.
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   407
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   408
// Object[] arr = new Integer[10];
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   409
// arr[0] = "Hello World";
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   410
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   411
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   412
// Scala gives you a compile-time error, which
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   413
// is much better.
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   414
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   415
var arr = Array[Int]()
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   416
arr(0) = "Hello World"
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   417
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   418
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   419
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   420
325
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   421
// Cool Stuff in Scala
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   422
//=====================
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   423
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   424
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   425
// Implicits or How to Pimp your Library
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   426
//======================================
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   427
//
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   428
// For example adding your own methods to Strings:
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   429
// Imagine you want to increment strings, like
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   430
//
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   431
//     "HAL".increment
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   432
//
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   433
// you can avoid ugly fudges, like a MyString, by
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   434
// using implicit conversions.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   435
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   436
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   437
implicit class MyString(s: String) {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   438
  def increment = s.map(c => (c + 1).toChar) 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   439
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   440
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   441
"HAL".increment
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   442
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   443
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   444
// Abstract idea:
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   445
// In that version implicit conversions were used to solve the 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   446
// late extension problem; namely, given a class C and a class T, 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   447
// how to have C extend T without touching or recompiling C. 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   448
// Conversions add a wrapper when a member of T is requested 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   449
// from an instance of C.
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   450
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   451
//Another example (TimeUnit in 2.13?)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   452
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   453
import scala.concurrent.duration.{TimeUnit,SECONDS,MINUTES}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   454
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   455
case class Duration(time: Long, unit: TimeUnit) {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   456
  def +(o: Duration) = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   457
    Duration(time + unit.convert(o.time, o.unit), unit)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   458
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   459
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   460
implicit class Int2Duration(that: Int) {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   461
  def seconds = new Duration(that, SECONDS)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   462
  def minutes = new Duration(that, MINUTES)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   463
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   464
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   465
5.seconds + 2.minutes   //Duration(125L, SECONDS )
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   466
2.minutes + 60.seconds
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   467
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   468
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   469
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   470
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   471
// Regular expressions - the power of DSLs in Scala
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   472
//==================================================
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   473
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   474
abstract class Rexp
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   475
case object ZERO extends Rexp                     // nothing
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   476
case object ONE extends Rexp                      // the empty string
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   477
case class CHAR(c: Char) extends Rexp             // a character c
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   478
case class ALT(r1: Rexp, r2: Rexp) extends Rexp   // alternative  r1 + r2
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   479
case class SEQ(r1: Rexp, r2: Rexp) extends Rexp   // sequence     r1 . r2  
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   480
case class STAR(r: Rexp) extends Rexp             // star         r*
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   481
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   482
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   483
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   484
// writing (ab)* in the format above is 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   485
// tedious
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   486
val r0 = STAR(SEQ(CHAR('a'), CHAR('b')))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   487
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   488
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   489
// some convenience for typing in regular expressions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   490
import scala.language.implicitConversions    
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   491
import scala.language.reflectiveCalls 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   492
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   493
def charlist2rexp(s: List[Char]): Rexp = s match {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   494
  case Nil => ONE
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   495
  case c::Nil => CHAR(c)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   496
  case c::s => SEQ(CHAR(c), charlist2rexp(s))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   497
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   498
implicit def string2rexp(s: String): Rexp = 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   499
  charlist2rexp(s.toList)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   500
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   501
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   502
val r1 = STAR("ab")
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   503
val r2 = STAR(ALT("ab", "baa baa black sheep"))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   504
val r3 = STAR(SEQ("ab", ALT("a", "b")))
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   505
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   506
implicit def RexpOps (r: Rexp) = new {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   507
  def | (s: Rexp) = ALT(r, s)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   508
  def % = STAR(r)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   509
  def ~ (s: Rexp) = SEQ(r, s)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   510
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   511
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   512
implicit def stringOps (s: String) = new {
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   513
  def | (r: Rexp) = ALT(s, r)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   514
  def | (r: String) = ALT(s, r)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   515
  def % = STAR(s)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   516
  def ~ (r: Rexp) = SEQ(s, r)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   517
  def ~ (r: String) = SEQ(s, r)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   518
}
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   519
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   520
//example regular expressions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   521
val digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   522
val sign = "+" | "-" | ""
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   523
val number = sign ~ digit ~ digit.% 
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   524
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   525
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   526
//
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   527
// Object Oriented Programming in Scala
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   528
//
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   529
// =====================================
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   530
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   531
abstract class Animal
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   532
case class Bird(name: String) extends Animal {
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   533
   override def toString = name
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   534
}
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   535
case class Mammal(name: String) extends Animal
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   536
case class Reptile(name: String) extends Animal
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   537
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   538
Bird("Sparrow")
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   539
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   540
println(Bird("Sparrow"))
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   541
println(Bird("Sparrow").toString)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   542
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   543
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   544
// you can override methods
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   545
case class Bird(name: String) extends Animal {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   546
  override def toString = name
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   547
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   548
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   549
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   550
// There is a very convenient short-hand notation
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   551
// for constructors:
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   552
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   553
class Fraction(x: Int, y: Int) {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   554
  def numer = x
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   555
  def denom = y
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   556
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   557
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   558
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   559
case class Fraction(numer: Int, denom: Int)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   560
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   561
val half = Fraction(1, 2)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   562
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   563
half.denom
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   564
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   565
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   566
// In mandelbrot.scala I used complex (imaginary) numbers 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   567
// and implemented the usual arithmetic operations for complex 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   568
// numbers.
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   569
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   570
case class Complex(re: Double, im: Double) { 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   571
  // represents the complex number re + im * i
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   572
  def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   573
  def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   574
  def *(that: Complex) = Complex(this.re * that.re - this.im * that.im,
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   575
                                 this.re * that.im + that.re * this.im)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   576
  def *(that: Double) = Complex(this.re * that, this.im * that)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   577
  def abs = Math.sqrt(this.re * this.re + this.im * this.im)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   578
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   579
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   580
val test = Complex(1, 2) + Complex (3, 4)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   581
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   582
// this could have equally been written as
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   583
val test = Complex(1, 2).+(Complex (3, 4))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   584
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   585
// this applies to all methods, but requires
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   586
import scala.language.postfixOps
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   587
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   588
List(5, 2, 3, 4).sorted
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   589
List(5, 2, 3, 4) sorted
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   590
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   591
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   592
// ...to allow the notation n + m * i
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   593
import scala.language.implicitConversions   
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   594
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   595
val i = Complex(0, 1)
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   596
implicit def double2complex(re: Double) = Complex(re, 0)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   597
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   598
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   599
val inum1 = -2.0 + -1.5 * i
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   600
val inum2 =  1.0 +  1.5 * i
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   601
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   602
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   603
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   604
// All is public by default....so no public is needed.
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   605
// You can have the usual restrictions about private 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   606
// values and methods, if you are MUTABLE !!!
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   607
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   608
case class BankAccount(init: Int) {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   609
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   610
  private var balance = init
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   611
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   612
  def deposit(amount: Int): Unit = {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   613
    if (amount > 0) balance = balance + amount
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   614
  }
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   615
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   616
  def withdraw(amount: Int): Int =
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   617
    if (0 < amount && amount <= balance) {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   618
      balance = balance - amount
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   619
      balance
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   620
    } else throw new Error("insufficient funds")
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   621
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   622
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   623
// BUT since we are completely IMMUTABLE, this is 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   624
// virtually of not concern to us.
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   625
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   626
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   627
243
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   628
// another example about Fractions
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   629
import scala.language.implicitConversions
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   630
import scala.language.reflectiveCalls
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   631
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   632
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   633
case class Fraction(numer: Int, denom: Int) {
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   634
  override def toString = numer.toString + "/" + denom.toString
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   635
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   636
  def +(other: Fraction) = Fraction(numer + other.numer, denom + other.denom)
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   637
  def /(other: Fraction) = Fraction(numer * other.denom, denom * other.numer)
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   638
  def /% (other: Fraction) = Fraction(numer * other.denom, denom * other.numer)
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   639
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   640
}
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   641
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   642
implicit def Int2Fraction(x: Int) = Fraction(x, 1)
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   643
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   644
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   645
val half = Fraction(1, 2)
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   646
val third = Fraction (1, 3)
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   647
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   648
half + third
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   649
half / third
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   650
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   651
// not sure if one can get this to work
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   652
// properly, since Scala just cannot find out
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   653
// if / is for ints or for Fractions 
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   654
(1 / 3) + half
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   655
(1 / 2) + third
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   656
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   657
// either you have to force the Fraction-type by
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   658
// using a method that is not defined for ints
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   659
(1 /% 3) + half
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   660
(1 /% 2) + third
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   661
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   662
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   663
// ...or explicitly give the type in order to allow
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   664
// Scala to do the conversion to Fractions 
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   665
((1:Fraction) / 3) + half
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   666
(1 / (3: Fraction)) + half
9bb36426c781 updated
Christian Urban <urbanc@in.tum.de>
parents: 242
diff changeset
   667
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   668
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   669
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   670
// DFAs in Scala  
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   671
//===============
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   672
import scala.util.Try
218
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   673
22705d22c105 updated
Christian Urban <urbanc@in.tum.de>
parents:
diff changeset
   674
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   675
// A is the state type
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   676
// C is the input (usually characters)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   677
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   678
case class DFA[A, C](start: A,              // starting state
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   679
                     delta: (A, C) => A,    // transition function
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   680
                     fins:  A => Boolean) { // final states (Set)
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   681
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   682
  def deltas(q: A, s: List[C]) : A = s match {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   683
    case Nil => q
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   684
    case c::cs => deltas(delta(q, c), cs)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   685
  }
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   686
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   687
  def accepts(s: List[C]) : Boolean = 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   688
    Try(fins(deltas(start, s))) getOrElse false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   689
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   690
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   691
// the example shown in the handout 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   692
abstract class State
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   693
case object Q0 extends State
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   694
case object Q1 extends State
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   695
case object Q2 extends State
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   696
case object Q3 extends State
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   697
case object Q4 extends State
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   698
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   699
val delta : (State, Char) => State = 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   700
  { case (Q0, 'a') => Q1
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   701
    case (Q0, 'b') => Q2
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   702
    case (Q1, 'a') => Q4
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   703
    case (Q1, 'b') => Q2
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   704
    case (Q2, 'a') => Q3
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   705
    case (Q2, 'b') => Q2
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   706
    case (Q3, 'a') => Q4
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   707
    case (Q3, 'b') => Q0
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   708
    case (Q4, 'a') => Q4
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   709
    case (Q4, 'b') => Q4 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   710
    case _ => throw new Exception("Undefined") }
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   711
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   712
val dfa = DFA(Q0, delta, Set[State](Q4))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   713
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   714
dfa.accepts("abaaa".toList)     // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   715
dfa.accepts("bbabaab".toList)   // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   716
dfa.accepts("baba".toList)      // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   717
dfa.accepts("abc".toList)       // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   718
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   719
// another DFA with a Sink state
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   720
abstract class S
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   721
case object S0 extends S
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   722
case object S1 extends S
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   723
case object S2 extends S
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   724
case object Sink extends S
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   725
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   726
// transition function with a sink state
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   727
val sigma : (S, Char) => S = 
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   728
  { case (S0, 'a') => S1
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   729
    case (S1, 'a') => S2
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   730
    case _ => Sink
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   731
  }
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   732
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   733
val dfa2 = DFA(S0, sigma, Set[S](S2))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   734
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   735
dfa2.accepts("aa".toList)        // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   736
dfa2.accepts("".toList)          // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   737
dfa2.accepts("ab".toList)        // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   738
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   739
//  we could also have a dfa for numbers
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   740
val sigmai : (S, Int) => S = 
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   741
  { case (S0, 1) => S1
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   742
    case (S1, 1) => S2
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   743
    case _ => Sink
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   744
  }
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   745
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   746
val dfa3 = DFA(S0, sigmai, Set[S](S2))
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   747
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   748
dfa3.accepts(List(1, 1))        // true
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   749
dfa3.accepts(Nil)               // false
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   750
dfa3.accepts(List(1, 2))        // false
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   751
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   752
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   753
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   754
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   755
// NFAs (Nondeterministic Finite Automata)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   756
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   757
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   758
case class NFA[A, C](starts: Set[A],          // starting states
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   759
                     delta: (A, C) => Set[A], // transition function
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   760
                     fins:  A => Boolean) {   // final states 
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   761
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   762
  // given a state and a character, what is the set of 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   763
  // next states? if there is none => empty set
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   764
  def next(q: A, c: C) : Set[A] = 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   765
    Try(delta(q, c)) getOrElse Set[A]() 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   766
242
e6b34f617915 updated
Christian Urban <urbanc@in.tum.de>
parents: 226
diff changeset
   767
  def nexts(qs: Set[A], c: C) : Set[A] =
e6b34f617915 updated
Christian Urban <urbanc@in.tum.de>
parents: 226
diff changeset
   768
    qs.flatMap(next(_, c))
e6b34f617915 updated
Christian Urban <urbanc@in.tum.de>
parents: 226
diff changeset
   769
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   770
  // depth-first version of accepts
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   771
  def search(q: A, s: List[C]) : Boolean = s match {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   772
    case Nil => fins(q)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   773
    case c::cs => next(q, c).exists(search(_, cs))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   774
  }
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   775
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   776
  def accepts(s: List[C]) : Boolean =
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   777
    starts.exists(search(_, s))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   778
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   779
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   780
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   781
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   782
// NFA examples
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   783
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   784
val nfa_trans1 : (State, Char) => Set[State] = 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   785
  { case (Q0, 'a') => Set(Q0, Q1) 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   786
    case (Q0, 'b') => Set(Q2) 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   787
    case (Q1, 'a') => Set(Q1) 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   788
    case (Q2, 'b') => Set(Q2) }
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   789
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   790
val nfa = NFA(Set[State](Q0), nfa_trans1, Set[State](Q2))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   791
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   792
nfa.accepts("aa".toList)             // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   793
nfa.accepts("aaaaa".toList)          // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   794
nfa.accepts("aaaaab".toList)         // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   795
nfa.accepts("aaaaabbb".toList)       // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   796
nfa.accepts("aaaaabbbaaa".toList)    // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   797
nfa.accepts("ac".toList)             // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   798
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   799
223
c6453f3547ec updated
Christian Urban <urbanc@in.tum.de>
parents: 222
diff changeset
   800
// Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs?
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   801
// A: Subset construction. Here the state type for the DFA is
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   802
//    sets of states.
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   803
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   804
def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   805
  DFA(nfa.starts, 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   806
      { case (qs, c) => nfa.nexts(qs, c) }, 
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   807
      _.exists(nfa.fins))
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   808
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   809
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   810
subset(nfa1).accepts("aa".toList)             // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   811
subset(nfa1).accepts("aaaaa".toList)          // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   812
subset(nfa1).accepts("aaaaab".toList)         // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   813
subset(nfa1).accepts("aaaaabbb".toList)       // true
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   814
subset(nfa1).accepts("aaaaabbbaaa".toList)    // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   815
subset(nfa1).accepts("ac".toList)             // false
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   816
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   817
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   818
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   819
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   820
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   821
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   822
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   823
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   824
// Lazy Evaluation
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   825
//=================
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   826
//
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   827
// Do not evaluate arguments just yet:
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   828
// this uses the => in front of the type
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   829
// of the code-argument
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   830
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   831
def time_needed[T](i: Int, code: => T) = {
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   832
  val start = System.nanoTime()
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   833
  for (j <- 1 to i) code
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   834
  val end = System.nanoTime()
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   835
  (end - start)/(i * 1.0e9)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   836
}
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   837
325
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   838
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   839
// Mind-Blowing Regular Expressions
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   840
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   841
// same examples using the internal regexes
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   842
val evil = "(a*)*b"
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   843
325
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   844
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   845
println("a" * 100)
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   846
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   847
("a" * 10 ++ "b").matches(evil)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   848
("a" * 10).matches(evil)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   849
("a" * 10000).matches(evil)
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   850
("a" * 20000).matches(evil)
226
5e489c9fe47b updated
Christian Urban <urbanc@in.tum.de>
parents: 225
diff changeset
   851
("a" * 50000).matches(evil)
222
e52cc402caee updated
Christian Urban <urbanc@in.tum.de>
parents: 218
diff changeset
   852
325
ca9c1cf929fa updated
Christian Urban <urbanc@in.tum.de>
parents: 320
diff changeset
   853
time_needed(1, ("a" * 10000).matches(evil))