Showing posts with label for. Show all posts
Showing posts with label for. Show all posts
Tuesday, January 26, 2010
Guard Sugar
This topic is a simple tip for a cleaner syntax for guards. Guards/filters are statements in for-comprehensions and case statements that guard or filter matches. Often you will see them as follows:
However you have the option to apply a little sugar to the statements cleaning them up a little:
As you can see the brackets are optional. That is because in both cases the brackets are not required for the parser to determine the start and end of the guard statements. They are added so that the "normal" syntax used in the typical if statements will compile.
- scala> for (i <- 1 to 10; if (i % 2 == 1)) yield i
- res0: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 3, 5, 7, 9)
- scala> util.Random.nextInt(10) match {
- | case i if(i>5) => println("hi")
- | case _ => println("low")
- | }
- low
However you have the option to apply a little sugar to the statements cleaning them up a little:
- scala> for (i <- 1 to 10; if i % 2 == 1) yield i
- res2: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 3, 5, 7, 9)
- scala> util.Random.nextInt(10) match {
- | case i if i>5 => println("hi")
- | case _ => println("low")
- | }
- hi
As you can see the brackets are optional. That is because in both cases the brackets are not required for the parser to determine the start and end of the guard statements. They are added so that the "normal" syntax used in the typical if statements will compile.
- scala> 10 match { case i if i == 1 || i == 10 => "obviously this is a match"}
- res4: java.lang.String = obviously this is a match
- /*
- In case statements you can split the if almost any way you want because it is very clearly bound by the if and the => that is required for all case statements with a guard
- */
- scala> 10 match { case i if i == 1 ||
- | i == 10 => "obviously this is a match"}
- res5: java.lang.String = obviously this is a match
- scala> 10 match {
- | case i
- | if
- | i == 1
- | ||
- | i == 10
- | => "matched"
- | }
- res6: java.lang.String = matched
- /*
- For-comprehensions are not as flexible since it is harder for the compiler to determine where the guard ends. So try to keep it on one line or otherwise make it a function. That is probably good advice for case statements as well.
- */
- scala> for {
- | x <- 1 to 10
- | if
- | x > 10
- | || x == 2 } yield x
- < console>:5: error: '<-' expected but integer literal found.
- || x == 2 } yield x
- ^
- < console>:5: error: illegal start of simple expression
- || x == 2 } yield x
- ^
- scala> for {
- | x <- 1 to 10
- | if x == 1 || x == 10 } yield x
- res7: scala.collection.immutable.IndexedSeq[Int] = IndexedSeq(1, 10)
Labels:
beginner,
filter,
for,
for-comprehension,
guard,
match,
matching,
Scala,
syntactic sugar
Monday, August 31, 2009
Java vs Scala Control Structures
This topic is mainly for completeness. We will quickly cover the standard control structures you find in Java and see how they are the same or different in Scala.
The first thing to note is that in Scala 2.7 there is no break keyword. In Scala 2.8 there is a break control structure but it is slightly different than the Java break keyword. We will encounter that topic in a later lesson. The control structures I will quickly cover are: do-while, while, for and if.
For information about the Java case statement take a look at the several matching topics covered now and in the future.
Note: The Java ternary if statement does not exist in Scala instead the standard if statement is to be used. It is slightly more verbose but returns a value in the same way as a ternary if statement.
The first thing to note is that in Scala 2.7 there is no break keyword. In Scala 2.8 there is a break control structure but it is slightly different than the Java break keyword. We will encounter that topic in a later lesson. The control structures I will quickly cover are: do-while, while, for and if.
For information about the Java case statement take a look at the several matching topics covered now and in the future.
Note: The Java ternary if statement does not exist in Scala instead the standard if statement is to be used. It is slightly more verbose but returns a value in the same way as a ternary if statement.
- scala> var i = 0;
- i: Int = 0
- scala> while( i<3 ){
- | println( i )
- | i += 1
- | }
- 0
- 1
- 2
- scala> i = 0
- i: Int = 0
- scala> do {
- | println( i )
- | i += 1
- | } while (i<3)
- 0
- 1
- 2
- scala> for(j <- 0 until 3) println (j)
- 0
- 1
- 2
- scala> if (i<3)
- more
- scala> val result = if (i<3)
- result: Int = 10
- scala> println (result)
- 10
- scala> if (i>10) println(1)
- scala> if (i<10)
- 1
- // Note that the return value is (). You can only get a meaningful return value if there is an else-clause.
- scala> val r = if (i<10)>
- r: Unit = ()
- scala> println(r)
- ()
Monday, August 17, 2009
Return values
As with most functional languages, most control structures ( if, for, try ) return values. The common java idiom:
can be replaced by
The benefit (other than less boiler plate code) is that name can now be a val instead of a var.
Another other point about returns: The return keyword is not required when returning a value from methods or control structures. The last value is always the return value. This is why you will get an error if the last line in a method or control structure is an assignment.
Examples:
- String name=null;
- if( xxx ) name="yyy";
- else name="zzz";
can be replaced by
- val name = if( xxx ) "yyy"; else "zzz";
The benefit (other than less boiler plate code) is that name can now be a val instead of a var.
Another other point about returns: The return keyword is not required when returning a value from methods or control structures. The last value is always the return value. This is why you will get an error if the last line in a method or control structure is an assignment.
Examples:
- scala> val name = if( 1==2 ) "Jesse" else "Mauricio"
- name: java.lang.String = Mauricio
- scala> println(name)
- Mauricio
- scala> val collection = for( i <- 1 to 100; if(i%20 == 3) ) yield i
- collection: Seq.Projection[Int] = RangeFM(3, 23, 43, 63, 83)
- scala> collection.foreach( i => print( i +" ") )
- 3 23 43 63 83
- scala> val someObj:AnyRef = "Hello"
- someObj: AnyRef = Hello
- scala> val choice = someObj match {
- | case _:java.io.File => "File"
- | case _:String => "String"
- | case _ => "Dunno"
- | }
- choice: java.lang.String = String
- scala> val result = try {
- | "two".toInt
- | }catch{
- | case e:NumberFormatException => -1
- | case _ => 0
- | }
- result: Int = -1
- scala> var i=0
- i: Int = 0
- // while and do-while do not have return values
- scala> while( i<4 ){
- | "22"
- | i += 2
- | }
- scala> println( if(i>0) "great" else "less" )
- great
- // code blocks return the last statement
- scala> val m = {
- | val x = 1
- | x + 2
- | }
- m: Int = 3
Tuesday, August 11, 2009
For-comprehensions
The for-comprehension construct is a very powerful way of iterating over collections. In its most basic form it is the java
for( var: collection){}
loop. As with all flow constructs in Scala, the scala for loop (or more correctly for-comprehension) can return a value. In the case of the for-comprehension it returns Unit (similar to void in Java terms) or a Sequence if yield is used.- scala> val range = 1 to 5
- range: Range.Inclusive = Range(1, 2, 3, 4, 5)
- // no return value if there is no 'yield' keyword
- scala> for( i <- 1 to 10 ) { i + 1 }
- // if there is a yield a collection is returned
- // the type of collection depends on the input
- // here a Range is returned
- scala> for( i <- range ) yield i+1
- res1: RandomAccessSeq.Projection[Int] = RangeM(2, 3, 4, 5, 6)
- // here a list is returned
- scala> for( i <- list( "a", "b", "c") ) yield "Word: "+i
- res1: List[java.lang.String] = List(Word: a, Word: b, Word: c)
- // you can filter the elements that visited in the loop
- scala> for( i <- range; if( i % 2 == 0) ) yield i
- res2: Seq.Projection[Int] = RangeFM(2, 4)
- // this is more about creating ranges than loops
- scala> for ( i <- 20 until (10,-2) ) yield i
- res3: RandomAccessSeq.Projection[Int] = RangeM(20, 18, 16, 14, 12)
- // you can string together multiple "generators"
- scala> for( i <- range; j <- range) yield (i,j)
- res4: Seq.Projection[(Int, Int)] = RangeG((1,1), (1,2), (1,3), (1,4), (1,5), (2,1), (2,2), (2,3), (2,4), (2,5), (3,1), (3,2), (3,3), (3,4), (3,5), (4,1), (4,2), (4,3), (4,4), (4,5), (5,1), (5,2), (5,3), (5\
- ,4), (5,5))
- // you can also declar variables as part of the loop declaration
- scala> for( i <- range; j <- 1 to i; k = i-j) yield k
- res5: Seq.Projection[Int] = RangeG(0, 1, 0, 2, 1, 0, 3, 2, 1, 0, 4, 3, 2, 1, 0)
- // with round brackets '(' and ')' multiple lines will require semi-colons
- scala> for (
- | i <- range;
- | j <- 1 to i;
- | k = i-j) yield k
- res6: Seq.Projection[Int] = RangeG(0, 1, 0, 2, 1, 0, 3, 2, 1, 0, 4, 3, 2, 1, 0)
- // with curly brackets '{' and '}' multiple lines you do not require semi-colons
- scala> for {
- | i <- range
- | j <- 1 to i
- | k = i-j}
- | yield{
- | k
- | }
- res7: Seq.Projection[Int] = RangeG(0, 1, 0, 2, 1, 0, 3, 2, 1, 0, 4, 3, 2, 1, 0)
- scala> for( i <- "enjoy" ) print(i)
- enjoy
Friday, August 7, 2009
Creating XML
Scala allows you to embed XML directly into a program and provides several ways to manipulate it. Today we will look at writing XML.
- scala> val xml = <root>
- | <child>text</child>
- | </root>
- xml: scala.xml.Elem =
- <root>
- <child>text</child>
- </root>
- scala> val data = "a string"
- data: java.lang.String = a string
- // you can embed logic and variables in the xml by surrounding with {}
- scala> val xml = <root>{data}</root>
- xml: scala.xml.Elem = <root>a string</root>
- scala> val xml = <root>{ for( i <- 1 to 3 ) yield {<xml i={i.toString}/>} } </root>
- xml: scala.xml.Elem = <root><xml i="1"></xml><xml i="2"></xml><xml i="3"></xml> </root>
- scala> val xml = <root>{ for( i <- 1 to 3 ) yield <child>{i}</child> } </root>
- xml: scala.xml.Elem = <root><child>1</child><child>2</child><child>3</child> </root>
- // save xml to file. Note Scala 2.8 is changin save API
- // and will require the encoding and DocType information
- scala> scala.xml.XML.save( "/tmp/doc.xml", xml)
Labels:
beginner,
for,
for-comprehension,
Scala,
xml
Monday, August 3, 2009
Basic Collection Operations
In this example I show some common operations that can be performed on all collections. The examples use list but any Iterable can be used.
- scala> val list = List(1,2,3,4)
- list: List[Int] = List(1, 2, 3, 4)
- scala> list.mkString(",")
- res0: String = 1,2,3,4
- scala> list.mkString("(",",",")")
- res1: String = (1,2,3,4)
- scala> list.reduceLeft ( (next,cumulative) => cumulative + next )
- res2: Int = 10
- scala> for( e <- list ) println ( e )
- 1 2 3 4
- scala> for( e <- list ) {
- | println ( e )
- | }
- 1 2 3 4
- scala> for( e <- list ) yield e+1
- res5: List[Int] = List(2, 3, 4, 5)
- scala> for ( e <- list; if( e % 2 == 0 ) ) yield e
- res6: List[Int] = List(2, 4)
Labels:
beginner,
collections,
for,
for-comprehension,
list,
Scala
Subscribe to:
Comments (Atom)