What does _ :: mean in Scala? - scala

I am going through a book Lift in action and I encountered something I don't quite understand: _ ::
object permanent_link extends MappedString(this, 150){
override def validations =
valMinLen(3, "Link URL must be at least 5 characters") _ ::
super.validations
}
I can't find any hint so I would be grateful if anyone could help me out..

I don't know Lift, but this is a general question. First of all, the :: is a Scala cons operator:
scala> 1 :: 2 :: List(3, 4)
res0: List[Int] = List(1, 2, 3, 4)
This means that super.validations is some sort of a sequence and valMinLen(3, "Link URL must be at least 5 characters") _ is a single value in that list.
From the context it looks obvious that in overridden validations method they are calling super version and prepend some extra validation at the beginning.
This extra validation is created by a call to valMinLen(). However this extra call does not return an element matching the type of validations list - but a function. Instead of prepending the function value we are explicitly saying (by adding _ suffix`) that we want to prepend a function itself, not a return value of that function.
Code snippet is worth a thousand words:
scala> def f = 3
f: Int
scala> def g = 4
g: Int
scala> val listOfInts = List(f, g)
listOfInts: List[Int] = List(3, 4)
scala> val listOfFunctions = List(f _, g _)
listOfFunctions: List[() => Int] = List(<function0>, <function0>)
Compare the type of listOfInts and listOfFunctions. I believe the f _ syntax is called partially applied function in Scala world.

The underscore ignifies that valMinLen isn't to be called but be used as a function "pointer".
The :: operator concatenates lists.
It would in other words seem like the code builds a list validations that consist of a function "pointer" to valMinLen with the parameters given and the rest of the list is the value of super.validations, that is the super class' validations.
I'm sure someone will correct my terminology here :)

The code might be more readable with some proper indentation and introducing a val:
object permanent_link extends MappedString(this, 150) {
override def validations = minimumValidation :: super.validations
val minimumValidation = valMinLen(3,"Link URL must be at least 5 characters") _
}
So as noted before, the :: operator just prepends a new element to a list, the _ has nothing to do with it and is used to obtain a function object, like in
(1 :: 2 :: Nil) map (println _)
which makes a list [1, 2] and applies the function println to every element (the underscore can actually be omitted here). The object println _ constructs a function object from the println method with the _ representing the function's single parameter.

Related

Scala convert List with unknown length to Tuple so pass it to Slick map clause

I have List in scala code which e.g i can receive from the specific method, and length of this list can vary from time to time, my target is converting this List to Tuple with same count of element:
val lst = someComputationHere()
val tupleLst = lstToTuple(lst)
clarification
//if lst.length = 2 --> Tuple2
//if lst.length = 3 --> Tuple3
//if lst.length = 4 --> Tuple4
...............
//if lst.length = N --> TupleN
and so on
p.s. I prefer don't use the reflection for solving this problem
UPD
My target is pass list with properties described above, to Slick map clause. Let's consider the next code snapshot:
query.map{ p=> (p.value1, p.value2, ... , p.valueN)}
Amount of this value is dinamic and i introduced this values to list:
val lst = someComputationHere()
val tuples = toTuples(lst)//Problem is here
query.map{_ => tuples}
Problem description: query.map{} - doen't pass the list, and as consequance, i must convert lst with changeable length N to Tuple with N elements
I don't know Slick, but if it only handles tuples it seems like a bad design choice for me. Even in Scala 2.12 there are no predefined types for tuples of arity greater than 22, although Scala will create them synthetically. So your best option is one big pattern match including all arities you need to support:
def toTuple[A](lst: List[A]): Product = lst match {
case _1 :: Nil => Tuple1(_1)
case _1 :: _2 :: Nil => Tuple2(_1, _2)
case _1 :: _2 :: _3 :: Nil => Tuple3(_1, _2, _3)
...
}
In generally you can't do this because tuple access methods _1, _2 etc have compile time checks (list size is undefined in compile time). But all tuples realises Product trait, where you can get element by its order:
(1, 2, 3).productElement(2) // returns 2
You can try to write method with next signature (maybe using macros)
List[T] => Product
method will be return TupleN where N is list size. For example, very primitive realisation:
list.length match {
case 1 => (list(0))
case 2 => (list(0), list(1))
...
case 22 => (list(0), list(1), ... ,list(21))
case _ => throw some exception...
}
After it in runtime you can try to cast your product to concrete TupleN type. But all this seems very dirty.

Flatten arbitrarily nested List in Scala

def flatten(l: List[_]): List[_] = {
def iflatten(l: List[_], ret: List[_]): List[_] = l match {
case Nil => ret
case h :: Nil =>
if( h.isInstanceOf[List[_]]) { iflatten(h, ret) }
else {
l.head :: ret
iflatten(l.tail, ret)
}
}
}
I know there are multiple ways to do this, and I'm not 100% sure my way is correct. I would like to test it but one issue I'm running into is in the second case statement where I call:
... { iflatten(h, ret) }
I am getting the compiler error:
error: type mismatch;
found : Unit
required: List[?]
I'm trying to work through these type issues to learn more about the typesystem as it's different than what I've worked with in the past. Any suggestions as to why the compiler is complaining would be greatly appreciated.
I'm not getting the same error you are concerning iflatten(h,ret).
I am getting the found : Unit; required : List[?] error, but it refers to the fact that you are not calling iflatten in flatten itself : after defining it, you need to call the function at the end of flatten's definition.
def flatten(l: List[_]): List[_] = {
def iflatten(l: List[_], ret: List[_]): List[_] = l match {
case Nil => ret
case (h:List[_]) :: tail => iflatten(tail,iflatten(h,ret))
case h :: tail => iflatten(tail,h::ret)
}
iflatten(l,List()).reverse
}
As for the code itself, you can (and should) verify types when matching.
Also note that the case h :: Nil only matches 1-length list.
As for the algorithm, you need to call iflatten within itself (that's where the arbitrarily nesting takes place).
I think you're just missing a cast.
if( h.isInstanceOf[List[_]]) { iflatten(h.asInstanceOf[List[_]], ret) }
Alternately: It would be prettier with pattern matching.
h match {
case hList: List[_] =>
iflatten(hList, ret)
case _ =>
l.head :: ret
iflatten(l.tail, ret)
}
(caveat: This is just off the top of my head and I haven't put anything through a compiler)
edit - Marth's solution of merging that into the previous pattern match looks better than mine.
Actually, I suspect the problem lies in the fact that you define the inner method iflatten, but never call it, so that the outer method flatten doesn't return anything (ie defaults to a return type of Unit, conflicting with the stated return type of List[_]).
Try adding the following as the last line of the outer flatten method:
iflatten(l, Nil)
Beyond that, you have various other problems with your code, such as not handling all match cases: you handle the case of a list with one element - h :: Nil - but not several elements. You probably meant something like h :: theRest, and then use theRest somewhere - probably as your ret parameter for the recursive call.
You also use the check h.isInstanceOf[List[_]] (generally any use of isInstanceOf is a bad code smell in scala) but then try passing h into iflatten recursively without casting it as List[_] (for example, as in #ChristopherMartin's answer, although using asInstanceOf is an even bigger code smell). #Marth's answer gives a good example of how to avoid these explicit type checks.
I think this is something the Shapeless library is good at.
https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/flatten.scala
Sorry, but this code is very complicated. I tried to simplify it and got to this solution:
scala> :paste
// Entering paste mode (ctrl-D to finish)
def flatten(l : List[_]) : List[_] = l flatMap {
case l1 : List[_] => flatten(l1)
case otherwise => List(otherwise)
}
// Exiting paste mode, now interpreting.
flatten: (l: List[_])List[_]
scala> flatten(List(1,2,3))
res3: List[Any] = List(1, 2, 3)
scala> flatten(List(1,2,List(3,4)))
res4: List[Any] = List(1, 2, 3, 4)
scala> flatten(List(List(1,List(2),3),4,List(4,5)))
res5: List[Any] = List(1, 2, 3, 4, 4, 5)
After fixing the code (adding the call to iflat), I did the following refactorings:
Removed the inner method
Used the built in flatMap for the iteration (and hence could eliminate or simplify some case expressions)
Replaced the instanceOf with type guards
I think a simpler solution would be using the shapeless library (hint: look for the "boilerplate" part).

Pattern Matching tuples in Scala

Trying to get a handle on pattern matching here-- coming from a C++/Java background it's very foreign to me.
The point of this branch is to check each member of a List d of tuples [format of (string,object). I want to define three cases.
1) If the counter in this function is larger than the size of the list (defined in another called acc), I want to return nothing (because there is no match)
2) If the key given in the input matches a tuple in the list, I want to return its value (or, whatever is stored in the tuple._2).
3) If there is no match, and there is still more list to iterate, increment and continue.
My code is below:
def get(key:String):Option[Any] = {
var counter: Int = 0
val flag: Boolean = false
x match {
case (counter > acc) => None
case ((d(counter)._1) == key) => d(counter)._2
case _ => counter += 1
}
My issue here is while the first case seems to compile correctly, the second throws an error:
:36: error: ')' expected but '.' found.
case ((d(counter)._1) == key) => d(counter)._2
The third as well:
scala> case _ => counter += 1
:1: error: illegal start of definition
But I assume it's because the second isn't correct. My first thought is that I'm not comparing tuples correctly, but I seem to be following the syntax for indexing into a tuple, so I'm stumped. Can anyone steer me in the right direction?
Hopefully a few things to clear up your confusion:
Matching in scala follows this general template:
x match {
case SomethingThatXIs if(SomeCondition) => SomeExpression
// rinse and repeat
// note that `if(SomeCondition)` is optional
}
It looks like you may have attempted to use the match/case expression as more of an if/else if/else kind of block, and as far as I can tell, the x doesn't really matter within said block. If that's the case, you might be fine with something like
case _ if (d(counter)._1 == key) => d(counter)._2
BUT
Some info on Lists in scala. You should always think of it like a LinkedList, where indexed lookup is an O(n) operation. Lists can be matched with a head :: tail format, and Nil is an empty list. For example:
val myList = List(1,2,3,4)
myList match {
case first :: theRest =>
// first is 1, theRest is List(2,3,4), which you can also express as
// 2 :: 3 :: 4 :: Nil
case Nil =>
// an empty list case
}
It looks like you're constructing a kind of ListMap, so I'll write up a more "functional"/"recursive" way of implementing your get method.
I'll assume that d is the backing list, of type List[(String, Any)]
def get(key: String): Option[Any] = {
def recurse(key: String, list: List[(String, Any)]): Option[Any] = list match {
case (k, value) :: _ if (key == k) => Some(value)
case _ :: theRest => recurse(key, theRest)
case Nil => None
}
recurse(key, d)
}
The three case statements can be explained as follows:
1) The first element in list is a tuple of (k, value). The rest of the list is matched to the _ because we don't care about it in this case. The condition asks if k is equal to the key we are looking for. In this case, we want to return the value from the tuple.
2) Since the first element didn't have the right key, we want to recurse. We don't care about the first element, but we want the rest of the list so that we can recurse with it.
3) case Nil means there's nothing in the list, which should mark "failure" and the end of the recursion. In this case we return None. Consider this the same as your counter > acc condition from your question.
Please don't hesitate to ask for further explanation; and if I've accidentally made a mistake (won't compile, etc), point it out and I will fix it.
I'm assuming that conditionally extracting part of a tuple from a list of tuples is the important part of your question, excuse me if I'm wrong.
First an initial point, in Scala we normally would use AnyRef instead of Object or, if worthwhile, we would use a type parameter which can increase reuse of the function or method and increase type safety.
The three cases you describe can be collapsed into two cases, the first case uses a guard (the if statement after the pattern match), the second case matches the entire non-empty list and searches for a match between each first tuple argument and the key, returning a Some[T] containing the second tuple argument of the matching tuple or None if no match occurred. The third case is not required as the find operation traverses (iterates over) the list.
The map operation after the find is used to extract the second tuple argument (map on an Option returns an Option), remove this operation and change the method's return type to Option[(String, T)] if you want the whole tuple returned.
def f[T](key: String, xs: List[(String, T)], initialCount: Int = 2): Option[T] = {
var counter = initialCount
xs match {
case l: List[(String, T)] if l.size < counter => None
case l: List[(String, T)] => l find {_._1 == key} map {_._2}
}
}
f("A", List(("A", 1), ("B", 2))) // Returns Some(1)
f("B", List(("A", 1), ("B", 2))) // Returns Some(2)
f("A", List(("A", 1))) // Returns None
f("C", List(("A", 1), ("B", 2))) // Returns None
f("C", Nil) // Returns None
First, why are you using a List for that reason? What you need is definitely a Map. Its get() returns None if key is not found and Some(value) if it is found in it.
Second, what is x in your example? Is it the list?
Third, you cannot write case (log) => .. where log is a logical condition, it is in the form of case _ if (log) => ... (as Rex Kerr already pinted out in his comment).
Fouth, you need a recursive function for this (simply increasing the counter will call this only on the second element).
So you'll need something like this (if still prefer sticking to List):
def get(l: List[Tuple2[String, String]], key: String): Option[String] = {
if (l.isEmpty) {
None
} else {
val act = l.head
act match {
case x if (act._1 == key) => Some(act._2)
case _ => get(l.tail, key)
}
}
}

How to extract remainder of sequence in pattern matching

I've obviously done a very poor job of explaining what I'm looking for in my original post so let's try this one more time. What I'm trying to accomplish is the ability to pass a sequence of items, extract one or more of the items, and then pass the REMAINDER of the sequence on to another extractor. Note that by sequence I mean sequence (not necessarily a List). My previous examples used list as the sequence and I gave some examples of extraction using cons (::), but I could just as well pass an Array as my sequence.
I thought I knew how pattern matching and extraction worked but I could be wrong so to avoid any more basic comments and links to how to do pattern matching sites here's my understanding:
If I want to return a single item from my extractor I would define an unapply method. This method takes whatever type I chose as input (the type could be a sequence...) and returns a single optional item (the return type could itself be a sequence). The return must be wrapped in Some if I want a match or None if I don't. Here is an example that takes a sequence as input and returns the same sequence wrapped in Some but only if it contains all Strings. I could very well just return the sequence wrapped in Some and not do anything else, but this seems to cause confusion for people. The key is if it is wrapped in Some then it will match and if it is None it will not. Just to be more clear, the match will also not happen unless the input also matches my unapply methods input type. Here is my example:
object Test {
// In my original post I just returned the Seq itself just to verify I
// had matched but many people commented they didn't understand what I
// was trying to do so I've made it a bit more complicated (e.g. match
// only if the sequence is a sequence of Strings). Hopefully I don't
// screw this up and introduce a bug :)
def unapply[A](xs: Seq[A]): Option[Seq[String]] =
if (xs forall { _.isInstanceOf[String] })
Some(xs.asInstanceOf[Seq[String]])
else
None
}
Using List as an example, I can now perform the following:
// This works
def test1(xs: List[_]) = xs match {
case (s: String) :: Test(rest) =>
println("s = " + s + ", rest = " + rest)
case _ =>
println("no match")
}
test1(List("foo", "bar", "baz")) // "s = foo, rest = List(bar, baz)"
My test1 function takes List as input and extracts the head and tail using cons via the constructor pattern (e.g. ::(s, rest)). It then uses type ascription (: String) to make sure the head (s) is a String. The tail contains List("bar", "baz"). This is a List which means it is also a Seq (sequence). It is then passed as input to my Test extractor which verifies that both "bar" and "baz" are strings and returns the List wrapped in Some. Since Some is returned it is considered a match (although in my original post where I inadvertently mixed up unapplySeq with unapply this didn't work as expected, but that aside...). This is NOT what I'm looking for. This was only an example to show that Test does in fact extract a Seq as input as expected.
Now, here's where I caused mass confusion last time when I inadvertently used unapplySeq instead of unapply in my write up. After much confusion trying to understand the comments that were posted I finally picked up on the mistake. Many thanks to Dan for pointing me in the right direction...
But just be avoid any more confusion, let me clarify my understanding of unapplySeq. Like unapply, unapplySeq takes in whatever argument I choose as input, but instead of returning a single element it returns a sequence of elements. Each item in this sequence can then be used for additional pattern matching. Again, to make a match happen the input type must match and my returned sequence must be wrapped in Some and not be None. When extracting over the sequence of items returned from unapplySeq, you can use _* to match any remaining items not yet matched.
Ok, so my extractor takes a sequence as input and returns a sequence (as a single item) in return. Since I only want to return a single item as a match I need to use unapply NOT unapplySeq. Even though in my case I'm returning a Seq, I don't want unapplySeq because I don't want to do more pattern matching on the items in the Seq. I just want to return the items as a Seq on its own to then be passed to the body of my case match. This sounds confusing, but to those that understand unapply vs unapplySeq I hope it isn't.
So here is what I WANT to do. I want to take something that returns a sequence (e.g. List or Array) and I want to extract a few items from this sequence and then extract the REMAINDER of the items (e.g. _*) as a sequence. Let's call it the remainder sequence. I want to then pass the remainder sequence as input to my extractor. My extractor will then return the remaining items as a single Seq if it matches my criteria. Just to be 100% clear. The List (or Array, etc) will have its unapplySeq extractor called to create the sequence of items. I will extract a one or more of these items and then pass what is left as a sequence to my Test extractor which will use unapply (NOT unapplySeq) to return the remainder. If you are confused by this, then please don't comment...
Here are my tests:
// Doesn't compile. Is there a syntax for this?
def test2(xs: Seq[_]) = xs match {
// Variations tried:
// Test(rest) # _* - doesn't compile (this one seems reasonable to me)
// Test(rest # _*) - doesn't compile (would compile if Test had
// unapplySeq, but in that case would bind List's
// second element to Test as a Seq and then bind
// rest to that Seq (if all strings) - not what I'm
// looking for...). I though that this might work
// since Scala knows Test has no unapplySeq only
// unapply so # _* can be tied to the List not Test
// rest # Test(_*) - doesn't compile (didn't expect to)
case List(s: String, Test(rest) # _*) =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
// This works, but messy
def test3(xs: List[_]) = xs match {
case List(s: String, rest # _*) if (
rest match { case Test(rest) => true; case _ => false }
) =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
I created test3 based on comments from Julian (thanks Julian..). Some have commented that test3 does what I want so they are confused what I'm looking for. Yes, it accomplishes what I want to accomplish, but I'm not satisfied with it. Daniel's example also works (thanks Daniel), but I'm also not satisfied with having to create another extractor to split things and then do embedded extractions. These solutions seem too much work in order to accomplish something that seems fairly straight forward to me. What I WANT is to make test2 work or know that it can't be done this way. Is the error given because the syntax is wrong? I know that rest # _* will return a Seq, that can be verified here:
def test4(xs: List[_]) = xs match {
case List(s: String, rest # _*) =>
println(rest.getClass) // scala.collection.immutable.$colon$colon
case _ =>
println("no match")
}
It returns cons (::) which is a List which is a Seq. So how can I pass the _* Seq on to my extractor and have is return bound to the variable rest?
Note that I've also tried passing varargs to my unapply constructor (e.g. unapply(xs: A*)...) but that won't match either.
So, I hope it is clear now when I say I want to extract the remainder of a sequence in pattern matching. I'm not sure how else I can word it.
Based on the great feedback from Daniel I'm hoping he is going to have an answer for me :)
I'd like to extract the first item and pass the remainder on to another extractor.
OK. Your test1 does that, exactly. first_item :: Extractor(the_rest). The weird behavior you're seeing comes from your Test extractor. As you already had the answer to your stated question, and as expected behavior from your Test strikes you as a problem with test1, it seems that what you really want is some help with extractors.
So, please read Extractor Objects, from docs.scala-lang.org, and Pattern Matching in Scala (pdf). Although that PDF has an example of unapplySeq, and suggests where you'd want to use it, here are some extra examples:
object Sorted {
def unapply(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
object SortedSeq {
def unapplySeq(xs: Seq[Int]) =
if (xs == xs.sortWith(_ < _)) Some(xs) else None
}
Interactively:
scala> List(1,2,3,4) match { case Sorted(xs) => Some(xs); case _ => None }
res0: Option[Seq[Int]] = Some(List(1, 2, 3, 4))
scala> List(4,1,2,3) match { case Sorted(xs) => Some(xs); case _ => None }
res1: Option[Seq[Int]] = None
scala> List(4,1,2,3) match { case first :: Sorted(rest) => Some(first, rest); case _ => None }
res2: Option[(Int, Seq[Int])] = Some((4,List(1, 2, 3)))
scala> List(1,2,3,4) match { case SortedSeq(a,b,c,d) => (a,b,c,d) }
res3: (Int, Int, Int, Int) = (1,2,3,4)
scala> List(4,1,2,3) match { case _ :: SortedSeq(a, b, _*) => (a,b) }
res4: (Int, Int) = (1,2)
scala> List(1,2,3,4) match { case SortedSeq(a, rest # _*) => (a, rest) }
res5: (Int, Seq[Int]) = (1,List(2, 3, 4))
Or maybe -- I only have the faint suspicion of this, you haven't said as much -- you don't want extractor help, but actually you want a terse way to express something like
scala> List(1,2,3,4) match { case 1 :: xs if (xs match { case Sorted(_) => true; case _ => false }) => xs }
res6: List[Int] = List(2, 3, 4)
Erlang has a feature like this (although, without these crazy extractors):
example(L=[1|_]) -> examine(L).
, which pattern-matches the same argument twice - to L and also to [1|_]. In Erlang both sides of the = are full-fledged patterns and could be anything, and you can add a third or more patterns with more =. Scala seems to only support the L=[1|_] form, having a variable and then a full pattern.
scala> List(4,1,2,3) match { case xs # _ :: Sorted(_) => xs }
collection.immutable.::[Int] = List(4, 1, 2, 3)
Well, the easiest way is this:
case (s: String) :: Test(rest # _*) =>
If you need this to work on general Seq, you can just define an extractor to split head from tail:
object Split {
def unapply[T](xs: Seq[T]): Option[(T, Seq[T])] = if (xs.nonEmpty) Some(xs.head -> xs.tail) else None
}
And then use it like
case Split(s: String, Test(rest # _*)) =>
Also note that if you had defined unapply instead of unapplySeq, then # _* would not be required on the pattern matched by Test.
:: is an extractor. For how it works (from a random googling), see, for example, here.
def test1(xs: List[_]) = xs match {
case s :: rest =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
scala> test1(List("a", "b", "c"))
s = a rest = List(b, c)
I think this is what you wanted?
Messing around with this, it seems that the issue has something to do with unapplySeq.
object Test {
def unapply[A](xs: List[A]): Option[List[A]] = Some(xs)
}
def test1(xs: List[_]) = xs match {
case (s: String) :: Test(s2 :: rest) =>
println("s = " + s + " rest = " + rest)
case _ =>
println("no match")
}
test1(List("foo", "bar", "baz"))
produces the output:
s = foo rest = List(baz)
I'm havng trouble googling up docs on the difference between unapply and unapplySeq.

Issues with maps and their entries in Scala

I have a recursive function that takes a Map as single parameter. It then adds new entries to that Map and calls itself with this larger Map. Please ignore the return values for now. The function isn't finished yet. Here's the code:
def breadthFirstHelper( found: Map[AIS_State,(Option[AIS_State], Int)] ): List[AIS_State] = {
val extension =
for(
(s, v) <- found;
next <- this.expand(s) if (! (found contains next) )
) yield (next -> (Some(s), 0))
if ( extension.exists( (s -> (p,c)) => this.isGoal( s ) ) )
List(this.getStart)
else
breadthFirstHelper( found ++ extension )
}
In extension are the new entries that shall get added to the map. Note that the for-statement generates an iterable, not a map. But those entries shall later get added to the original map for the recursive call. In the break condition, I need to test whether a certain value has been generated inside extension. I try to do this by using the exists method on extension. But the syntax for extracting values from the map entries (the stuff following the yield) doesn't work.
Questions:
How do I get my break condition (the boolean statement to the if) to work?
Is it a good idea to do recursive work on a immutable Map like this? Is this good functional style?
When using a pattern-match (e.g. against a Tuple2) in a function, you need to use braces {} and the case statement.
if (extension.exists { case (s,_) => isGoal(s) } )
The above also uses the fact that it is more clear when matching to use the wildcard _ for any allowable value (which you subsequently do not care about). The case xyz gets compiled into a PartialFunction which in turn extends from Function1 and hence can be used as an argument to the exists method.
As for the style, I am not functional programming expert but this seems like it will be compiled into a iterative form (i.e. it's tail-recursive) by scalac. There's nothing which says "recursion with Maps is bad" so why not?
Note that -> is a method on Any (via implicit conversion) which creates a Tuple2 - it is not a case class like :: or ! and hence cannot be used in a case pattern match statement. This is because:
val l: List[String] = Nil
l match {
case x :: xs =>
}
Is really shorthand/sugar for
case ::(x, xs) =>
Similarly a ! b is equivalent to !(a, b). Of course, you may have written your own case class ->...
Note2: as Daniel says below, you cannot in any case use a pattern-match in a function definition; so while the above partial function is valid, the following function is not:
(x :: xs) =>
This is a bit convoluted for me to follow, whatever Oxbow Lakes might think.
I'd like first to clarify one point: there is no break condition in for-comprehensions. They are not loops like C's (or Java's) for.
What an if in a for-comprehension means is a guard. For instance, let's say I do this:
for {i <- 1 to 10
j <- 1 to 10
if i != j
} yield (i, j)
The loop isn't "stopped" when the condition is false. It simply skips the iterations for which that condition is false, and proceed with the true ones. Here is another example:
for {i <- 1 to 10
j <- 1 to 10
if i % 2 != 0
} yield (i, j)
You said you don't have side-effects, so I can skip a whole chapter about side effects and guards on for-comprehensions. On the other hand, reading a blog post I made recently on Strict Ranges is not a bad idea.
So... give up on break conditions. They can be made to work, but they are not functional. Try to rephrase the problem in a more functional way, and the need for a break condition will be replaced by something else.
Next, Oxbow is correct in that (s -> (p,c) => isn't allowed because there is no extractor defined on an object called ->, but, alas, even (a :: b) => would not be allowed, because there is no pattern matching going on in functional literal parameter declaration. You must simply state the parameters on the left side of =>, without doing any kind of decomposition. You may, however, do this:
if ( extension.exists( t => val (s, (p,c)) = t; this.isGoal( s ) ) )
Note that I replaced -> with ,. This works because a -> b is a syntactic sugar for (a, b), which is, itself, a syntactic sugar for Tuple2(a, b). As you don't use neither p nor c, this works too:
if ( extension.exists( t => val (s, _) = t; this.isGoal( s ) ) )
Finally, your recursive code is perfectly fine, though probably not optimized for tail-recursion. For that, you either make your method final, or you make the recursive function private to the method. Like this:
final def breadthFirstHelper
or
def breadthFirstHelper(...) {
def myRecursiveBreadthFirstHelper(...) { ... }
myRecursiveBreadthFirstHelper(...)
}
On Scala 2.8 there is an annotation called #TailRec which will tell you if the function can be made tail recursive or not. And, in fact, it seems there will be a flag to display warnings about functions that could be made tail-recursive if slightly changed, such as above.
EDIT
Regarding Oxbow's solution using case, that's a function or partial function literal. It's type will depend on what the inference requires. In that case, because that's that exists takes, a function. However, one must be careful to ensure that there will always be a match, otherwise you get an exception. For example:
scala> List(1, 'c') exists { case _: Int => true }
res0: Boolean = true
scala> List(1, 'c') exists { case _: String => true }
scala.MatchError: 1
at $anonfun$1.apply(<console>:5)
... (stack trace elided)
scala> List(1, 'c') exists { case _: String => true; case _ => false }
res3: Boolean = false
scala> ({ case _: Int => true } : PartialFunction[AnyRef,Boolean])
res5: PartialFunction[AnyRef,Boolean] = <function1>
scala> ({ case _: Int => true } : Function1[Int, Boolean])
res6: (Int) => Boolean = <function1>
EDIT 2
The solution Oxbow proposes does use pattern matching, because it is based on function literals using case statements, which do use pattern matching. When I said it was not possible, I was speaking of the syntax x => s.