progs/lecture4.scala
changeset 223 c6453f3547ec
parent 222 e52cc402caee
child 224 42d760984496
equal deleted inserted replaced
222:e52cc402caee 223:c6453f3547ec
    47 
    47 
    48 val ls = List(1,2,3,3,2,4,3,2,1)
    48 val ls = List(1,2,3,3,2,4,3,2,1)
    49 ls.distinct
    49 ls.distinct
    50 
    50 
    51 
    51 
    52 def distinctBy[B, C](xs: List[B], f: B => C, acc: List[C] = Nil): List[B] = xs match {
    52 def distinctBy[B, C](xs: List[B], 
       
    53                      f: B => C, 
       
    54                      acc: List[C] = Nil): List[B] = xs match {
    53   case Nil => Nil
    55   case Nil => Nil
    54   case (x::xs) => {
    56   case x::xs => {
    55     val res = f(x)
    57     val res = f(x)
    56     if (acc.contains(res)) distinctBy(xs, f, acc)  
    58     if (acc.contains(res)) distinctBy(xs, f, acc)  
    57     else x::distinctBy(xs, f, res::acc)
    59     else x::distinctBy(xs, f, res::acc)
    58   }
    60   }
    59 } 
    61 } 
    60 
    62 
       
    63 // distinctBy  with the identity function is 
       
    64 // just distinct
    61 distinctBy(ls, (x: Int) => x)
    65 distinctBy(ls, (x: Int) => x)
    62 
    66 
    63 
    67 
    64 val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd')
    68 val cs = List('A', 'b', 'a', 'c', 'B', 'D', 'd')
    65 
    69 
    68 
    72 
    69 
    73 
    70 // Type inference is local in Scala
    74 // Type inference is local in Scala
    71 
    75 
    72 def id[T](x: T) : T = x
    76 def id[T](x: T) : T = x
    73 
       
    74 
    77 
    75 val x = id(322)          // Int
    78 val x = id(322)          // Int
    76 val y = id("hey")        // String
    79 val y = id("hey")        // String
    77 val z = id(Set(1,2,3,4)) // Set[Int]
    80 val z = id(Set(1,2,3,4)) // Set[Int]
    78 
    81 
    83 // - variance (OO)
    86 // - variance (OO)
    84 // - bounds (subtyping)
    87 // - bounds (subtyping)
    85 // - quantification
    88 // - quantification
    86 
    89 
    87 // Java has issues with this too: Java allows
    90 // Java has issues with this too: Java allows
    88 // to write the following, but raises an exception
    91 // to write the following incorrect code, and
    89 // at runtime
    92 // only recovers by raising an exception
    90 
    93 // at runtime.
    91 //Object[] arr = new Integer[10];
    94 
    92 //arr[0] = "Hello World";
    95 // Object[] arr = new Integer[10];
       
    96 // arr[0] = "Hello World";
    93 
    97 
    94 
    98 
    95 // Scala gives you a compile-time error
    99 // Scala gives you a compile-time error
    96 
   100 
    97 var arr = Array[Int]()
   101 var arr = Array[Int]()
   110 abstract class Animal
   114 abstract class Animal
   111 case class Bird(name: String) extends Animal
   115 case class Bird(name: String) extends Animal
   112 case class Mammal(name: String) extends Animal
   116 case class Mammal(name: String) extends Animal
   113 case class Reptile(name: String) extends Animal
   117 case class Reptile(name: String) extends Animal
   114 
   118 
   115 println(new Bird("Sparrow"))
   119 println(Bird("Sparrow"))
   116 println(Bird("Sparrow").toString)
   120 println(Bird("Sparrow").toString)
   117 
   121 
   118 
   122 
   119 // you can override methods
   123 // you can override methods
   120 case class Bird(name: String) extends Animal {
   124 case class Bird(name: String) extends Animal {
   136 val half = Fraction(1, 2)
   140 val half = Fraction(1, 2)
   137 
   141 
   138 half.denom
   142 half.denom
   139 
   143 
   140 
   144 
   141 // in mandelbrot.scala I used complex (imaginary) numbers and implemented
   145 // In mandelbrot.scala I used complex (imaginary) numbers 
   142 // the usual arithmetic operations for complex numbers
   146 // and implemented the usual arithmetic operations for complex 
       
   147 // numbers.
   143 
   148 
   144 case class Complex(re: Double, im: Double) { 
   149 case class Complex(re: Double, im: Double) { 
   145   // represents the complex number re + im * i
   150   // represents the complex number re + im * i
   146   def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
   151   def +(that: Complex) = Complex(this.re + that.re, this.im + that.im)
   147   def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
   152   def -(that: Complex) = Complex(this.re - that.re, this.im - that.im)
   161 
   166 
   162 List(5, 2, 3, 4).sorted
   167 List(5, 2, 3, 4).sorted
   163 List(5, 2, 3, 4) sorted
   168 List(5, 2, 3, 4) sorted
   164 
   169 
   165 
   170 
   166 // to allow the notation n + m * i
   171 // ...to allow the notation n + m * i
   167 import scala.language.implicitConversions   
   172 import scala.language.implicitConversions   
       
   173 
   168 object i extends Complex(0, 1)
   174 object i extends Complex(0, 1)
   169 implicit def double2complex(re: Double) = Complex(re, 0)
   175 implicit def double2complex(re: Double) = Complex(re, 0)
   170 
   176 
   171 
   177 
   172 val inum1 = -2.0 + -1.5 * i
   178 val inum1 = -2.0 + -1.5 * i
   173 val inum2 =  1.0 +  1.5 * i
   179 val inum2 =  1.0 +  1.5 * i
   174 
   180 
   175 
   181 
   176 
   182 
   177 // all is public by default....so no public
   183 // All is public by default....so no public is needed.
   178 // you can have the usual restrictions about private values
   184 // You can have the usual restrictions about private 
   179 // and methods, if you are MUTABLE(!!!)
   185 // values and methods, if you are MUTABLE !!!
   180 
   186 
   181 case class BankAccount(init: Int) {
   187 case class BankAccount(init: Int) {
   182 
   188 
   183   private var balance = init
   189   private var balance = init
   184 
   190 
   191       balance = balance - amount
   197       balance = balance - amount
   192       balance
   198       balance
   193     } else throw new Error("insufficient funds")
   199     } else throw new Error("insufficient funds")
   194 }
   200 }
   195 
   201 
   196 // BUT since we are IMMUTABLE, this is virtually of not 
   202 // BUT since we are completely IMMUTABLE, this is 
   197 // concern to us.
   203 // virtually of not concern to us.
   198 
   204 
   199 
   205 
   200 
   206 
   201 
   207 
   202 
   208 
   205 
   211 
   206 
   212 
   207 // A is the state type
   213 // A is the state type
   208 // C is the input (usually characters)
   214 // C is the input (usually characters)
   209 
   215 
   210 case class DFA[A, C](start: A,               // starting state
   216 case class DFA[A, C](start: A,              // starting state
   211                      delta: (A, C) => A,     // transition function
   217                      delta: (A, C) => A,    // transition function
   212                      fins:  A => Boolean) {  // final states
   218                      fins:  A => Boolean) { // final states (Set)
   213 
   219 
   214   def deltas(q: A, s: List[C]) : A = s match {
   220   def deltas(q: A, s: List[C]) : A = s match {
   215     case Nil => q
   221     case Nil => q
   216     case c::cs => deltas(delta(q, c), cs)
   222     case c::cs => deltas(delta(q, c), cs)
   217   }
   223   }
   246 dfa.accepts("abaaa".toList)     // true
   252 dfa.accepts("abaaa".toList)     // true
   247 dfa.accepts("bbabaab".toList)   // true
   253 dfa.accepts("bbabaab".toList)   // true
   248 dfa.accepts("baba".toList)      // false
   254 dfa.accepts("baba".toList)      // false
   249 dfa.accepts("abc".toList)       // false
   255 dfa.accepts("abc".toList)       // false
   250 
   256 
   251 // another DFA test with a Sink state
   257 // another DFA with a Sink state
   252 abstract class S
   258 abstract class S
   253 case object S0 extends S
   259 case object S0 extends S
   254 case object S1 extends S
   260 case object S1 extends S
   255 case object S2 extends S
   261 case object S2 extends S
   256 case object Sink extends S
   262 case object Sink extends S
   257 
   263 
   258 // transition function with a sink state
   264 // transition function with a sink state
   259 val sigma : (S, Char) :=> S = 
   265 val sigma : (S, Char) => S = 
   260   { case (S0, 'a') => S1
   266   { case (S0, 'a') => S1
   261     case (S1, 'a') => S2
   267     case (S1, 'a') => S2
   262     case _ => Sink
   268     case _ => Sink
   263   }
   269   }
   264 
   270 
   266 
   272 
   267 dfa2.accepts("aa".toList)        // true
   273 dfa2.accepts("aa".toList)        // true
   268 dfa2.accepts("".toList)          // false
   274 dfa2.accepts("".toList)          // false
   269 dfa2.accepts("ab".toList)        // false
   275 dfa2.accepts("ab".toList)        // false
   270 
   276 
       
   277 //  we could also have a dfa for numbers
       
   278 val sigmai : (S, Int) => S = 
       
   279   { case (S0, 1) => S1
       
   280     case (S1, 1) => S2
       
   281     case _ => Sink
       
   282   }
       
   283 
       
   284 val dfa3 = DFA(S0, sigmai, Set[S](S2))
       
   285 
       
   286 dfa3.accepts(List(1, 1))        // true
       
   287 dfa3.accepts(Nil)               // false
       
   288 dfa3.accepts(List(1, 2))        // false
       
   289 
   271 
   290 
   272 
   291 
   273 
   292 
   274 // NFAs (Nondeterministic Finite Automata)
   293 // NFAs (Nondeterministic Finite Automata)
   275 
   294 
   276 
   295 
   277 case class NFA[A, C](starts: Set[A],           // starting states
   296 case class NFA[A, C](starts: Set[A],          // starting states
   278                      delta: (A, C) => Set[A],  // transition function
   297                      delta: (A, C) => Set[A], // transition function
   279                      fins:  A => Boolean) {    // final states 
   298                      fins:  A => Boolean) {   // final states 
   280 
   299 
   281   // given a state and a character, what is the set of 
   300   // given a state and a character, what is the set of 
   282   // next states? if there is none => empty set
   301   // next states? if there is none => empty set
   283   def next(q: A, c: C) : Set[A] = 
   302   def next(q: A, c: C) : Set[A] = 
   284     Try(delta(q, c)) getOrElse Set[A]() 
   303     Try(delta(q, c)) getOrElse Set[A]() 
   285 
       
   286   def nexts(qs: Set[A], c: C) : Set[A] =
       
   287     qs.flatMap(next(_, c))
       
   288 
   304 
   289   // depth-first version of accepts
   305   // depth-first version of accepts
   290   def search(q: A, s: List[C]) : Boolean = s match {
   306   def search(q: A, s: List[C]) : Boolean = s match {
   291     case Nil => fins(q)
   307     case Nil => fins(q)
   292     case c::cs => next(q, c).exists(search(_, cs))
   308     case c::cs => next(q, c).exists(search(_, cs))
   314 nfa.accepts("aaaaabbb".toList)       // true
   330 nfa.accepts("aaaaabbb".toList)       // true
   315 nfa.accepts("aaaaabbbaaa".toList)    // false
   331 nfa.accepts("aaaaabbbaaa".toList)    // false
   316 nfa.accepts("ac".toList)             // false
   332 nfa.accepts("ac".toList)             // false
   317 
   333 
   318 
   334 
   319 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs
   335 // Q: Why the kerfuffle about the polymorphic types in DFAs/NFAs?
   320 // A: Subset construction
   336 // A: Subset construction
   321 
   337 
   322 def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = {
   338 def subset[A, C](nfa: NFA[A, C]) : DFA[Set[A], C] = {
   323   DFA(nfa.starts, 
   339   DFA(nfa.starts, 
   324       { case (qs, c) => nfa.nexts(qs, c) }, 
   340       { case (qs, c) => nfa.nexts(qs, c) },