I started learning scala a few days ago and when learning it, I am comparing it with other functional programming languages like (Haskell, Erlang) which I had some familiarity with. Does Scala has guard sequences available?
I went through pattern matching in Scala, but is there any concept equivalent to guards with otherwise and all?
Yes, it uses the keyword if. From the Case Classes section of A Tour of Scala, near the bottom:
def isIdentityFun(term: Term): Boolean = term match {
case Fun(x, Var(y)) if x == y => true
case _ => false
}
(This isn't mentioned on the Pattern Matching page, maybe because the Tour is such a quick overview.)
In Haskell, otherwise is actually just a variable bound to True. So it doesn't add any power to the concept of pattern matching. You can get it just by repeating your initial pattern without the guard:
// if this is your guarded match
case Fun(x, Var(y)) if x == y => true
// and this is your 'otherwise' match
case Fun(x, Var(y)) if true => false
// you could just write this:
case Fun(x, Var(y)) => false
Yes, there are pattern guards. They're used like this:
def boundedInt(min:Int, max: Int): Int => Int = {
case n if n>max => max
case n if n<min => min
case n => n
}
Note that instead of an otherwise-clause, you simply specifiy the pattern without a guard.
The simple answer is no. It is not exactly what you are looking for (an exact match for Haskell syntax). You would use Scala's "match" statement with a guard, and supply a wild card, like:
num match {
case 0 => "Zero"
case n if n > -1 =>"Positive number"
case _ => "Negative number"
}
I stumbled to this post looking how to apply guards to matches with multiple arguments, it is not really intuitive, so I am adding an random example here.
def func(x: Int, y: Int): String = (x, y) match {
case (_, 0) | (0, _) => "Zero"
case (x, _) if x > -1 => "Positive number"
case (_, y) if y < 0 => "Negative number"
case (_, _) => "Could not classify"
}
println(func(10,-1))
println(func(-10,1))
println(func(-10,0))
Related
I've been working with Scala for a while and it still troubles me a lot. I don't know why they made it so complex. I am trying to understand matching case classes when there are only two members for this case class
def main(args: Array[String]): Unit = {
case class X(a: String, i: Int)
def doSome(x: X): Unit = {
x match {
case "x" X 1 => print("ahhh") // <---- HERE !
case X(_, _) => println("")
}
}
doSome(X("x", 1))
case class Y(a: String, i: Int, j: Int)
def doAnother(y:Y): Unit = {
y match {
case "y" X 1 => print("ahhh") // how to make similar syntax when there are more than one syntax ?
case Y(_, _,_) => println("") // this is understandable
}
}
doAnother(Y("y", 1,2))
}
How can the syntax "x" X 1 match X("x",1) and if "x" X 1 can match match X("x",1) then what matches Y("y",1,2), obviously "y" Y 1 Y 2 doesn't work?
What is so special about the first argument if we can match on "y" Y (1,2)?
At least in case of List it feels more natural to me, for example consider
List(42, 11) match {
case head :: tail =>
case Nil =>
}
as opposed to
List(42, 11) match {
case ::(head, tail) =>
case Nil =>
}
where head :: tail communicates directly the shape of the List.
As a side note, infix notation can sometimes communicate intent more clearly, for example, consider syntax of generalised constraints
implicitly[List[Int] <:< Iterable[Int]] // infix type notation seems more natural
implicitly[<:<[List[Int], Iterable[Int]]]
You don't have to use a language feature just because it is there.
In this case I can see no reason not to use the standard class matching version:
x match {
case X("x", 1) => print("ahhh")
case _ => println("")
}
}
y match {
case Y("y", 1, _) => print("ahhh")
case _ => println("")
}
Ok, so the thing I was looking for is called "Infix Types". From Scala for Impatient, 2nd edition
An infix type is a type with two type parameters, written in “infix”
syntax, with the type name between the type parameters. For example,
you can write String Map Int instead of Map[String, Int] The
infix notation is common in mathematics. For example, A × B = { (a, b)
| a Œ A, b Œ B } is the set of pairs with components of types A and B.
In Scala, this type is written as (A, B). If you prefer the
mathematical notation, you can define type ×[A, B] = (A, B) Then you
can write String × Int instead of (String, Int). All infix type
operators have the same precedence. As with regular operators, they
are left-associative unless their names end in :. For example,
String × Int × Int means ((String, Int), Int). This type is similar
to, but not the same, as (String, Int, Int), which could not be
written in infix form in Scala.
To answer your query on What is so special about the first argument if we can match on "y" Y (1,2)?: this is because of how your case class gets decomposed via its unapply method.
The preferred way of matching against a case class is how you've done in the second statement of both your methods.
However, for Y, the preferred way to match would be case Y("y", 1, 2) as mentioned in Tim's comment.
For X, a few ways you can use power of pattern matching are (similarly for Y):
case X("x", 1) => ???
case X(a, 1) => ???
case X(_, 1) => ???
case X("x", _) => ???
case x#X("x", _) =>
case X(a, b) if b > 5 => ???
The following, however, is a very bad style as it compromises readability and hence maintainability of the code
case "x" X 1 => print("ahhh")
As Mario mentioned, the way you're using pattern matching is more suited for lists instead of case classes, as it makes your code consistent with the way a list is structured (head cons tail), and thus enhances readability.
You can go through following articles for a more deeper understanding on how to exploit the power of scala's pattern matching:
https://www.artima.com/pins1ed/case-classes-and-pattern-matching.html
https://docs.scala-lang.org/tour/pattern-matching.html
https://docs.scala-lang.org/overviews/scala-book/match-expressions.html
I am new to scala. I was writing a pattern matching as below:
val capitals = Map("France" -> "Paris", "Japan" -> "Tokyo")
show(capitals.get("test"))
def show(x: Option[String]) = x match {
case Some(s) | None => s
}
I am getting error:
Error: illegal variable in pattern alternative
case Some(s) | None => s
^
I am trying to see how can I achieve or condition like I have in if statement in java
if (str == null || str.isEmpty())
Can you help rewrite the code or point out the mistake?
Question: How do I mention or condition in a case pattern matching?
This is how you pattern match on Options:
def show(x: Option[String]) = x match {
case Some(s) => s
case None => "N/A"
}
(by the way, you can also do something like this):
capitals.get("test").getOrElse("N/A")
Now, to add OR conditions to a pattern match case, you cannot use bound variables. This will work, however:
def show(x: Option[String]) = x match {
case Some(_) | None => "a"
}
Note that the only difference is in Some(_) as opposed to your Some(s). Using Some(s) wouldn't make much sense because you can't reuse that s anyway (what if None comes, what would s be in that case?)
I think this is what you are trying to achieve. If s has a value in the map return, s. If s has no value in the map, return a message indicating so.
val capitals = Map("France" -> "Paris", "Japan" -> "Tokyo")
def show(x: Option[String]) = x match {
case Some(s) => s
case None => "x has no value"
}
show(capitals.get("mani"))
A similar and more concise version of show is capitals.get("mani").getOrElse("No value found") which returns
No value found.
Further, you can use a guards to check various conditions on s such as if the first char is upper case. This first case will only match if s begins with an upper case character.
def show(x: Option[String]) = x match {
case Some(s) if(s.head.isUpper) => s
case None => "No value"
}
Matching Some(s) | None doesn't make sense, as if (true || false) (just no-op as it doesn't dispatch cases).
x match {
case Some(s) => println(s"Some($s)")
case _ => println("_None")
}
The most direct solution is using the method defined for maps, which takes the default as the second argument:
capitals.getOrElse("test","N/A")
I use a Scala plugin for IntelliJ IDEA, and I have found a weird behaviour of that plugin. Let me show you a code snippet:
def fun: Option[Any] => Int = {
case Some(x) if x.isInstanceOf[Int] => x.asInstanceOf[Int]
case None => 0
}
Regarding the Scala code, IDEA gives me a warning:
Comparing unrelated types
Detects comparisons (== and !=) of expressions which cannot be the same type
and it highlights the next statement x.isInstanceOf[Int]. I use isInstanceOf operator just to determine a type of x. Is this a bug of the plugin or I missed something in Scala syntax?
Use getOrElse(0) for this operation.
Edit :
You are geting this error as Some(x) is not same as Int.
But you are making condition direct over here as Some(x) first and then directly checking whether the instance is of Int,so they are basically not of same type(Int and Some)
case Some(x) if x.isInstanceOf[Int] => x.asInstanceOf[Int]
To avoid this warning:
You can do something like this if you want to keep it as Option[Any] as Input.
def fun(x:Option[Any]):Int = x match {
case x:Some[Int] => x.get
case x => 0
}
Otherwise,if you know that input will be Option[Int] then
use it as parameter.
def fun(x:Option[Int]):Int = x match {
case x:Some[Int] => x.get
case None => 0
}
I do not get a similar warning, but something very important you should be aware of is that your code is not "case statement" complete and has potential holes. Should you pass it Some("String") for example, none of your case lines can handle this. Potential fixes:
def fun: Option[Any] => Int = {
case Some(x) => if (x.isInstanceOf[Int]) x.asInstanceOf[Int] else 0
case None => 0
}
or
def fun: Option[Any] => Int = {
case Some(x) if x.isInstanceOf[Int] => x.asInstanceOf[Int]
case Some(other) => 0
case None => 0
}
I know that parametric polymorphism is what actually works, but I'm curious why using Any in it's place does not. For example how is the first function
def len[T] (l:List[T]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
different from this one?
def len (l:List[Any]):Int =
l match {
case Nil => 0
case _ :: t => 1 + len(t)
}
What do you mean it doesn't work? This seems fine:
len(List('a,'b,'c))
// res0: Int = 3
Your in your example, there really isn't a difference, since you're not actually using the contents of the list for anything, but imagine a slightly different function:
def second[T](l: List[T]): Option[T] =
l match {
case Nil => None
case _ :: Nil => None
case _ :: x :: _ => Some(x)
}
println(second(List(1,2,3)).map(_ + 5)) // Some(7)
println(second(List(List('a,'b,'c), List('d,'e))).map(_.head)) // Some('d)
If you tried this with Any, you wouldn't be able to get anything except Option[Any] in return, so the compiler wouldn't let you do anything useful with the result (like add it to an Int or call .head, as in the examples, respectively).
In this case there really isn't a difference, because you aren't relying on the contained type at all, just the structure of List itself. It doesn't matter what T is, the length will be the same either way.
The type parameter would be important if you wanted to return another List[T]. For example:
def takeEveryOther[T](l: List[T]): List[T] =
l.zipWithIndex.collect { case (a, i) if(i % 2 == 0) => a }
I'm looking to match a sequence within a sequence like either in ex 1 or ex 2;
List(1, 2, 3, 4) match {
case 1 :: List(_*) :: 4 :: tail => // Ex 1
case 1 :: (seq : List[Int]) :: 4 :: tail => // Ex 2
case _ =>
}
This is a variant to the fixed length sequence pattern _*. Like the _*, I don't care about the content of the inner pattern, but it is important that the length can vary and that the pattern is surrounded by a prefix (such as the 1 above) and a suffix (like the 4).
My question is if any of you have a trick to do this by some crafty unapply magic or if you'd just iterate the list to search for the sequence manually.
Thanks in advance! :-)
This is really outside the scope of what pattern matching is supposed to be used for. Even if you could finagle a set of custom unapply methods to do what you wanted, it wouldn't be apparent whether matching was greedy or not, etc..
However, if you really want to, you can proceed as follows (for example):
import scala.collection.SeqLike
class Decon[A](a0: A, a1: A) {
def unapply[C <: SeqLike[A, C]](xs: C with SeqLike[A, C]): Option[(C, C)] = {
xs.span(_ != a1) match {
case (a0 +: pre, a1 +: post) => Some((pre,post))
case _ => None
}
}
}
val Dc = new Decon(1,4)
scala> List(1,2,3,4,5) match { case Dc(pre, post) => (pre, post); case _ => (Nil, Nil) }
res1: (List[Int], List[Int]) = (List(2, 3),List(5))
Separating the specification of the fixed elements 1 and 4 from the match is necessary; otherwise the normal algorithm would ask the unapply to return values without any knowledge of what was being sought, and then would test to make sure they were correct.
You could do something like this:
List(1,2,3,4) match {
case 1 :: tail if tail.last == 4 => println("Found it!")
}
But if you check the implementation of last in LinearSeqOptimized:
def last: A = {
if (isEmpty) throw new NoSuchElementException
var these = this
var nx = these.tail
while (!nx.isEmpty) {
these = nx
nx = nx.tail
}
these.head
}
It is iterating indeed. This is because List inherits from LinearSeq which are optimized to provide efficient head and tail operations. For what you want to do, it is better to use an IndexedSeq implementation like Vector which has an optimized length operation, used in last:
override /*TraversableLike*/ def last: A = {
if (isEmpty) throw new UnsupportedOperationException("empty.last")
apply(length-1)
}
So you could do something like this:
Vector(1,2,3,4) match {
case v if v.head == 1 && v.last == 4 => println("Found it!")
}