99 Problems in Scala

Just another WordPress.com weblog

Enums in Scala

Posted by rbpasker on April 25, 2009

Amazingly enough, no example of how to do this is in either Programming in Scala or on the Scala-lang.org website.

there are a few Scala-isms here.

First, since there’s no member variables in State, a trait is more appropriate than a class.

Second, by using the keyword “sealed,” you specify that no other instances of this trait will be found in any other source file. That means that the code generated for the match expression doesn’t need an “default”, and you are guaranteed that the match will always have a case to choose from.

Lastly, by specifying the case classes as “object” you get a singleton subclass for each discrete state.

sealed trait State
case object Closed extends State
case object Open extends State
case object Interrupted extends State



scala> val theState:State=Open
theState: State = Open

scala> theState match
{
case Open => println("o")
case Closed => println("c")
case Interrupted => println("i")
}
o

Posted in Uncategorized | 1 Comment »

P11 (*) Modified run-length encoding.

Posted by rbpasker on April 20, 2009

 def encodeModified[T] (l :List[T]) : List[Any] = {

pack(l).map(sublist => if (sublist.length==1) sublist.head else (sublist.length, sublist.head))

}
| | | | encodeModified: [T](List[T])List[Any]

scala> encodeModified(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
res7: List[Any] = List((4,'a), 'b, (2,'c), (2,'a), 'd, (4,'e))

Posted in Uncategorized | Leave a Comment »

P10 =- Run-length encoding of a list.

Posted by rbpasker on April 20, 2009


scala> def encode[T] (l :List[T]) : List[(Int, T)] = {

pack(l).map(sublist => (sublist.length, sublist.head))

}
| | | | encode: [T](List[T])List[(Int, T)]

scala> encode(List(‘a, ‘a, ‘a, ‘a, ‘b, ‘c, ‘c, ‘a, ‘a, ‘d, ‘e, ‘e, ‘e, ‘e))

res3: List[(Int, Symbol)] = List((4,’a), (1,’b), (2,’c), (2,’a), (1,’d), (4,’e))

Posted in Uncategorized | Leave a Comment »

P09 – Pack consecutive duplicates of list elements into sublists.

Posted by rbpasker on April 20, 2009

scala> pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
res0: List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))

def pack[T](l : List[T]) : List[List[T]] = {

def pack2(result : List[List[T]], current : List[T], l : List[T]) : List[List[T]] = l match {
case h::t if (current.head == h) => pack2(result, h::current, t)
case h::t => pack2(result + current, List(h), t)
case Nil => result + current
}

l match {
case Nil => Nil
case head::tail=> pack2(List(), List(head), tail)
}

}

Posted in Uncategorized | Leave a Comment »

P08 – Eliminate consecutive duplicates of list elements.

Posted by rbpasker on April 19, 2009

scala> compress(List(‘a, ‘a, ‘a, ‘a, ‘b, ‘c, ‘c, ‘a, ‘a, ‘d, ‘e, ‘e, ‘e, ‘e))
res0: List[Symbol] = List(‘a, ‘b, ‘c, ‘a, ‘d, ‘e)

def compress[T](l : List[T]) : List[T] = l match {
case head::next::tail if (head == next) => compress(next::tail)
case head::tail => head::compress(tail)
case nil => List()
}

Posted in Uncategorized | Leave a Comment »

P07 — Flatten a nested list structure.

Posted by rbpasker on April 19, 2009

here’s the example:

scala> flatten(List(List(1, 1), 2, List(3, List(5, 8))))
res0: List[Any] = List(1, 1, 2, 3, 5, 8)

This tells me that the the List head could be itself a List that needs to be flattened, so I have to differentiate between a head that is a List and a head that is not a List.

def flatten[_](l: List[_]) : List[_] = l match {
case (head: List[_])::Nil => flatten(head)
case (head: List[_])::tail => flatten(head):::flatten(tail)
case head::Nil => List(head)
case head::tail => head::flatten(tail)
case Nil => Nil
}

Posted in Uncategorized | Leave a Comment »

P06 – Find out whether a list is a palindrome.

Posted by rbpasker on April 16, 2009

Another easy one, we just use reverse()!

scala> def isPalindrome[T](l: List[T]) : Boolean = l match {
case Nil => true
case _::Nil => true
case h::t => (h == t.reverse.head)
}
isPalindrome: [T](List[T])Boolean

scala> isPalindrome(List(1, 2, 3, 2, 1))
res29: Boolean = true

scala> isPalindrome(List(1, 2, 3, 2, 2))
res30: Boolean = false

scala> isPalindrome(List())
res31: Boolean = true

scala> isPalindrome(List(1,2,1))
res32: Boolean = true

scala> isPalindrome(List(1,2,2))
res33: Boolean = false

And their answer is:

def isPalindrome[T](l: List[T]): Boolean = l == l.reverse

Which tells me i should have looked to see if List has a equality method, which it does: List.equals. But what we see here is not .equals but .==.

Scala departs from Java’s idea of equality by defining == not as reference equality (a==b iff a and b are references to the identical object), but as a synonym for .equals!

The Java behavior of reference equality has been moved to the .eq method.

Posted in Uncategorized | 3 Comments »

P05 — Reverse a list

Posted by rbpasker on April 16, 2009

Should be pretty simple:

scala> def reverse[T](l: List[T]) : List[T] = l match {
| case Nil => Nil
| case h::Nil => h
| case h::t => reverse(t)::h
| }
:7: error: value :: is not a member of T
case h::t => reverse(t)::h
^

Hmmm, :: isn’t the List append operator. Lets try +

scala> def reverse[T](l: List[T]) : List[T] = l match {
case Nil => Nil
case h::Nil => List(h)
case h::t => reverse(t)+h
}

| | | | warning: there were deprecation warnings; re-run with -deprecation for details
reverse: [T](List[T])List[T]

scala> reverse(List())
res13: List[Nothing] = List()

scala> reverse(List(1))
res14: List[Int] = List(1)

scala> reverse(List(1,2,3,4,5,6))
res15: List[Int] = List(6, 5, 4, 3, 2, 1)

Voilá, but what about the deprecation warnings?

It looks like + was deprecated, so I again asked on the Scala IRC channel about it, but nobody seemed to have a definitive answer why it was deprecated. Someone did suggestion using ::: instead, and cautioned that it associates right-to-left. Normally, when you see a+b it means a.+(b), which is like saying a.add(b) in Java. That’s because operators are left associative, meaning they are a function of the parameter on the left. Being right-associative, ::: associates with the parameter with on the right, so a:::b means b.:::(a), which you might read as b.append(a), if you were reading Java. It took a bit of searching in the Scala Language Reference to find out why:

The associativity of an operator is determined by the operator’s last character. Operators ending in a colon ‘:’ are right-associative. All other operators are left-associative. (6.12.3 Infix Operations)

So, in fact a:::b is not the “append” operation on a, but the “prepend” operation on b. This is also true for ::.

Note that + takes a List[T] and appends an element of type T, but ::: tales two parameters of type List[T], so we’ll have to wrap the matched head element in a List.

So let’s try changing + to :::, and at the time see if we can’t shorten up our solution, since reverse(t), when t is Nil, is still Nil.

scala> def reverse[T](l: List[T]) : List[T] = l match {
case Nil => Nil
case h::t => reverse(t):::List(h)
}

reverse: [T](List[T])List[T]

scala> reverse(List(1,2,3,4,5,6,7))
res24: List[Int] = List(7, 6, 5, 4, 3, 2, 1)

scala> reverse(List(1))
res25: List[Int] = List(1)

scala> reverse(List())
res26: List[Nothing] = List()

Very nice.

The first answer is identical to our own, but there are two more answers. Answer two is the “tail recursive” version as per the previous post.

The third answer, however, is labelled as “Pure functional”:


def reverse[T](l: List[T]): List[T] = l.foldLeft(List[T]())((r, h) => h :: r)

Wow, I have no idea how to read that!

AND, I thought my answers were functional, but they are not functional enough!

According to the docs, foldLeft is defined as

Combines the elements of this list together using the binary function f, from left to right, and starting with the value z.

I take this to mean that if you have List(a, b, c, d) and the binary function +, then fold left means ((a+b)+c)+d).

So List[T]() is the type of the binary function which we want to use, and it returns a List[T]. At the end of the def is ((r, h) => h :: r), which is the definition of the binary function. Since r and h are swapped and appended, lets call this function swap. So folding left with a swap on List(a,b,c,d), we get:

((a swap b) swap c) swap d)
((b, a) swap c) swap d)
((c, b, a) swap d)
(d, c, b, a)

And again we have a reversed List!

So even though it was an easy exercise, we learned that a trailing colon on an operator means it associates right, and we learned how to pass functions to other functions!

Posted in Uncategorized | 2 Comments »

P04 – Find the number of elements of a list

Posted by rbpasker on April 16, 2009

This one should be pretty easy, since we already know from the last problem how to get to the nth element.


scala> def length[T](l: List[T]) : Int = l match {
| case Nil => 0
| case e::Nil => 1
| case _::t => 1 + length(t)
| }
length: [T](List[T])Int

scala> length(List())
res7: Int = 0

scala> length(List(1))
res8: Int = 1

scala> length(List(1,2,3,4,5,6,7,8))
res10: Int = 8

There are two functional answers to this problem.

The first is a “simple recursive” solution:


def length[T](l: List[T]): Int = l match {
case Nil => 0
case _ :: tail => 1 + length(tail)
}

I see now that I didn’t need the middle case case e::Nil => 1, because the last case would have properly copmuted length(Nil) as 0.

The second answer, however, is more interesting and also somewhat disappointing. It says

Unfortunately, the JVM doesn’t do tail-call elimination in the general case. Scala *will* do it if the method is either final or is a local function.

Which means that all the work I’ve been doing to get out of the imperative (iterative) style, as per P01’s admonition about the “functional approach” which uses recursion, was a nice exercise, but frankly nearly futile in Scala because these functions, given a large enough List, will blow the stack. Luckily their answer to P04 links to a blog with a way to get tail recursion in Scala, and frankly, its not pretty. It involves some special maneuvers which you can read about there.

Posted in Uncategorized | Leave a Comment »

P03 – Find the Kth element of a list

Posted by rbpasker on April 16, 2009

This problem takes me back to the Peano Axioms, which I learned in high school. The 5th and 6th axiom state (recursively):

5) 0 is a natural number.
6) For every natural number n, S(n) is a natural number, where S() is a successor function.

Which means that S(0) is 1, and S(S(0)) is 2, etc.

Therefore, the kth element must be that element which is found at k recursions of _::tail, or a NoSuchElementException, if there are too few elements.

So instead of matching and recursing on l, we’ll match and recurse on k:


scala> def nth[T](n:Int, l:List[T]) : T = n match {
case 0 => l::_
case >0 => nth(n-1,l.tail)
:3: error: ‘=>’ expected but integer literal found.
case >0 => nth(n-1,l.tail)
^

Ooops. I can’t just say >0 to match k>0.

I would like to say I figure out how to put an inequality into a case on my own, but after a fair bit of research I couldn’t figure out how to do it, so I asked on the Scala IRC channel” (irc://irc.freenode.org/scala) channel how express trichotomy in a match and got this answer:

case 0 => e;case n if n < f;case n if n > 0 => g

Section 8.4 of the Scala reference manual says that a case expression can have an optional “Guard”, which is an expression, after the pattern match.

OK, so I would have to go back to matching on the List, and add a guard:

scala> def nth[T](n:Int, l:List[T]) : T = l match {
case e::t if n==0 => e
case e::t if n>0 => nth(n-1,t)
case _ => throw new NoSuchElementException
}
nth: [T](Int,List[T])T

The first case (n==0) means that we have reached the nth element, and so return the head of the list. Also, my match e::t should have used a wildcard e::_ instead because the tail is thrown away in the action.

The second case means we have ‘n’ more elements to go, so recurse with n=n-1 and remove the head element. Again, I should have used a wildcard _::t because the head is not used.

The last case matches anything else, which means n<0, so there must not have been enough elements in the list.

Lets see how it worked:

scala> nth(2, List(1, 1, 2, 3, 5, 8))
res5: Int = 2

scala> nth(4, List(1, 1, 2, 3, 5, 8))
res6: Int = 5

scala> nth(22, List(1, 1, 2, 3, 5, 8))
java.util.NoSuchElementException

scala> nth(0,List())
java.util.NoSuchElementException

Pretty good!

Now lets look at the “functional” answer to Problem 3:

def nth[T](n: Int, l: List[T]): T = (n, l) match {
case (0, e :: _ ) => e
case (n, _ :: tail) => nth(n - 1, tail)
case (_, Nil ) => throw new NoSuchElementException
}

Interesting! They matched a List consisting of (n, l), and instead of checking to see if k was <0, they checked for an empty list (in the 3d case).

So, from my answer, I learned about guard expressions in pattern matches, and from their answer, I learned that you can cons up a List, and match against multiple values.

Posted in Uncategorized | Leave a Comment »