I have an Option[A] and I want to say: If it's a None then computes another Option[A], otherwise stay as is. getOrElse[A] accepts an A (I need to pass an Option[A]) and flatMap applies to the Some case (I want to handle the None case) . Essentially I want the following code but in the most succinct way possible:
val a: Option[A] = ???
a match {
case None => ??? // returns an Option[A] here
case Some(x) => a
}
This is embarrassing.
For other lazy people out there like myself the answer is orElse
Related
I am having problems understanding how TypeTests in scala3 can replace the use of TypeTag in scala 2. The usecase being able to match on a generic parameter like x: List[Int].
Concrete example I am trying to solve:
enum Foo :
case Bar()
case Baz()
case class Mod[T <: Foo](modFn: T => T)
def modifyBarsOrBaz(mod: Mod[_]) = mod match
case barMod: Mod[Foo.Bar] => ???
case bazMod: Mod[Foo.Baz] => ???
the compilation results (as expected) in the comiler warning(s)
the type test for Mod[Foo.Bar] cannot be checked at runtime and an unreachable case.
Now my question is: is this possible to do at all in scala3?
I was under the impression that I would somehow have to provide a TypeTest[Any, Mod[Foo.X]] for all X which are subclasses of the Foo enum.
But I am struggling to even implement those tests, as well as understanding what using parameter the modifyBarsOrBaz is required for this to work.
Thus I came up with the following (not working) solution:
def modifyBarsOrBaz[T <: Foo](mod: Mod[T])(using TypeTest[Any, Mod[T]]) = mod match
case barMod: Mod[Foo.Bar] => ???
case bazMod: Mod[Foo.Baz] => ???
and a naive tt implementation as such
val tt: TypeTest[Any, Mod[Foo.Bar]] =
new TypeTest[Any, Mod[Foo.Bar]] :
def unapply(x: Any): Option[x.type & Mod[Foo.Bar]] = x match
case m: Mod[_] => ??? // what to do here? use a classtag on Mod?
I tried to search the web for answers, but since this is pretty new I was not lucky. Any hints?
The problem here is that a TypeTest[Any, Mod[T]] will be able to check if an Any is a Mod[T], not to check whether or not a Mod[T] is a Mod[Foo.Bar] or a Mod[Foo.Baz]. What you would need are TypeTest[Any, Mod[Foo.Bar] and TypeTest[Any, Mod[Foo.Baz]:
def modifyBarsOrBaz(mod: Mod[?])(using asBar: TypeTest[Any, Mod[Foo.Bar]], asBaz: TypeTest[Any, Mod[Foo.Baz]]) =
mod match
case asBar(barMod) => println("barMod")
case asBaz(bazMod) => println("bazMod")
I don't know why a simple barMod: Mod[Foo.Bar] didn't work with a TypeTest[Any, Mod[Foo.Bar]] in scope, I'll come to that later.
However, you now have to actually implement those TypeTests yourself. Since the JVM doesn't have reification, you will have to store information about T in the Mod class. If you really want to keep Mod a single case class, you can do this:
type BarOrBaz[T <: Foo] <: String = T match {
case Foo.Bar => "Bar"
case Foo.Baz => "Baz"
}
case class Mod[T <: Foo](modFn: T => T, tag: BarOrBaz[T])
TypeTest instances for Bar and Baz can now be provided with an inline method:
import compiletime.constValue
inline given [T <: Foo]: TypeTest[Mod[?], Mod[T]] = new TypeTest:
def unapply(mod: Mod[?]) = Option.when(mod.tag == constValue[BarOrBaz[T]])(mod.asInstanceOf[mod.type & Mod[T]])
modifyBarsOrBaz would be
def modifyBarsOrBaz(mod: Mod[?])(using asBar: TypeTest[Mod[Foo], Mod[Foo.Bar]], asBaz: TypeTest[Mod[Foo], Mod[Foo.Baz]]) = mod match
case asBar(barMod) => println("barMod")
case asBaz(bazMod) => println("bazMod")
For convenience, an inline apply method could be made:
object Mod:
inline def apply[T <: Foo](modFn: T => T) = new Mod(modFn, constValue[BarOrBaz[T]])
And you could use it like this (Scastie):
modifyBarsOrBaz(Mod[Foo.Bar](bar => bar)) //barMod
modifyBarsOrBaz(Mod[Foo.Baz](baz => baz)) //bazMod
But really, the need for type tests such as this feels like a code smell to me. I'd suggest rethinking your design to work around it rather than use tags like this.
I am writing a filter function in Scala and although I feel good about what I am trying to do I can not figure out why it will not recognize my List or what this bug is telling me. I have tried editing the syntax but nothing seems to fix it
sealed trait List[+A]
case object Empty extends List[Nothing]
case class Cons[A]( x : A, xs : List[A]) extends List[A]
def filter[A](f: A => Boolean, list: List[A]): List[A] =
for {
a <- list
if (f(a))
} yield a
<console>:93: error: value filter is not a member of List[A]
a <- list
Check out code here
So, if we first understand that for comprehensions are sugar syntax for map, flatMap and filter. Then we can see that your attempt of defining filter is equivalent to:
list.filter(a => f(a))
Which obviously doesn't make sense.
You can not define filter in terms of filter...
Well, you actually can, that is what recursion is all about, and actually that is the correct way of solving the problem.
With the extra help of pattern matching.
So a recursive function is the best way to process a recursive data structure like List.
The process is actually quite straight forward, we need to figure out what to do in the base case and what to do in the recursive case (which probably will require a recursive call).
(note: I changed the function signature, this new signature allows better syntax and better type inference)
/** Returns a new list with only the elements that satisfied the predicate. **/
def filter[A](list: List[A])(p: A => Boolean): List[A] = list match {
case Empty => ??? // Base case. Tip: tink in what is the filter of an empty list.
case Cons(a, tail) => ??? // Recursive case. Tip: you probably will need to call the function recursively.
}
Once you fill the holes, you will have a proper filter function. But, we got a problem, since this is a recursive solution, trying to filter a very big list will result in a StackOverflowError which is not ideal, so what can we do?
Tail-Recursion to the rescue!
The idea is simple, we need to keep an accumulator for holding intermediate values.
(note: it is usually a good idea to keep the tail function as an inner function)
/** Returns a new list with only the elements that satisfied the predicate. **/
def filter[A](list: List[A])(p: A => Boolean): List[A] = {
#annotation.tailrec
def loop(remaining: List[A], acc: ???): List[A] =
remaining match {
case Cons(a, as) => ??? // Recursive case.
case Empty => ??? // Base case, we are done! Tip: Is the output correct?
}
loop(remaining = list, acc = ???)
}
Once you fill the holes, you will have a good filter function.
(Final note: Following a technique called type tetris probably will help to get the correct solution)
First of all, I have a suggestions for you -
Don't use semicolons in Scala.
Use camelCase for variable names in Scala. (You can use CAPITAL_SNAKE_CASE for constants though).
Use CapitalCamelCase for trait, class and object names.
Now, you are naming your paramter as List which conflicts with class List.
So, your code need to be changed to this,
def filter[A](f: A => Boolean, list: List[A]): List[A] =
for {
a <- list
if (f(a))
} yield a
// use the defined method to filter the list
filter[Int](i => i > 2, List(1,2,3,4))
I am writing a filter function in Scala and although I feel good about what I am trying to do I can not figure out why it will not recognize my List or what this bug is telling me. I have tried editing the syntax but nothing seems to fix it
sealed trait List[+A]
case object Empty extends List[Nothing]
case class Cons[A]( x : A, xs : List[A]) extends List[A]
def filter[A](f: A => Boolean, list: List[A]): List[A] =
for {
a <- list
if (f(a))
} yield a
<console>:93: error: value filter is not a member of List[A]
a <- list
Check out code here
So, if we first understand that for comprehensions are sugar syntax for map, flatMap and filter. Then we can see that your attempt of defining filter is equivalent to:
list.filter(a => f(a))
Which obviously doesn't make sense.
You can not define filter in terms of filter...
Well, you actually can, that is what recursion is all about, and actually that is the correct way of solving the problem.
With the extra help of pattern matching.
So a recursive function is the best way to process a recursive data structure like List.
The process is actually quite straight forward, we need to figure out what to do in the base case and what to do in the recursive case (which probably will require a recursive call).
(note: I changed the function signature, this new signature allows better syntax and better type inference)
/** Returns a new list with only the elements that satisfied the predicate. **/
def filter[A](list: List[A])(p: A => Boolean): List[A] = list match {
case Empty => ??? // Base case. Tip: tink in what is the filter of an empty list.
case Cons(a, tail) => ??? // Recursive case. Tip: you probably will need to call the function recursively.
}
Once you fill the holes, you will have a proper filter function. But, we got a problem, since this is a recursive solution, trying to filter a very big list will result in a StackOverflowError which is not ideal, so what can we do?
Tail-Recursion to the rescue!
The idea is simple, we need to keep an accumulator for holding intermediate values.
(note: it is usually a good idea to keep the tail function as an inner function)
/** Returns a new list with only the elements that satisfied the predicate. **/
def filter[A](list: List[A])(p: A => Boolean): List[A] = {
#annotation.tailrec
def loop(remaining: List[A], acc: ???): List[A] =
remaining match {
case Cons(a, as) => ??? // Recursive case.
case Empty => ??? // Base case, we are done! Tip: Is the output correct?
}
loop(remaining = list, acc = ???)
}
Once you fill the holes, you will have a good filter function.
(Final note: Following a technique called type tetris probably will help to get the correct solution)
First of all, I have a suggestions for you -
Don't use semicolons in Scala.
Use camelCase for variable names in Scala. (You can use CAPITAL_SNAKE_CASE for constants though).
Use CapitalCamelCase for trait, class and object names.
Now, you are naming your paramter as List which conflicts with class List.
So, your code need to be changed to this,
def filter[A](f: A => Boolean, list: List[A]): List[A] =
for {
a <- list
if (f(a))
} yield a
// use the defined method to filter the list
filter[Int](i => i > 2, List(1,2,3,4))
I have scala function that looks like this:
Now, depending upon the type of T (In my case, it can be Double, Boolean and LocalDate),
I need to apply functions on ob. Something like this (I know the code will make no sense but I am trying to convey what I mean to do):
def X[T](ob: Observable[T]): Observable[T] = {
//code
T match {
case Double => DoSomething1(ob:Observable[Double]):Observable[Double]
case Boolean => DoSomething2(ob:Observable[Boolean]):Observable[Boolean]
case LocalDate => DoSomething3(ob:Observable[LocalDate]):Observable[LocalDate]
}
}
Taking into consideration the Erasure property of Scala, can reflection be somehow used to get the job done? Is it even possible?
I would go with TypeTag if you're on 2.10+
import reflect.runtime.universe._
class Observable[Foo]
def X[T: TypeTag](ob: Observable[T]) = ob match {
case x if typeOf[T] <:< typeOf[Double] => println("Double obs")
case x if typeOf[T] <:< typeOf[Boolean] => println("Boolean obs")
case x if typeOf[T] <:< typeOf[Int] => println("Int obs")
}
X(new Observable[Int])
// Int obs
See also this lengthy, but awesome answer
Note also that I only took a glimpse at scala reflection, so likely somebody may write a better example of TypeTag usage.
While dealing with Option in Scala what are the things I should be considering to decide whether to map or patten match? For example, if I have Option[MyClass], I can deal with it the following ways:
def getList(myOptionInstance: Option[MyClass]): List[String] =
myOptionInstance map (...) getOrElse(List.empty[String])
or
def getList(myOptionInstance: Option[MyClass]): List[String] = myOptionInstance match {
case Some(mySomeInstance) => .....
case None => List.empty[String]
}
When will I choose one over the other?
I second #rarry: fold is the preferred way to deal with this.
Some prefer pattern matching because it's "cool" (whatever it means) and sometimes easier to read.
I try to avoid using getOrElse because it does not force you to use the same type for the default value as the type wrapped in your Option:
def getOrElse[B >: A](default: ⇒ B): B
So you can write:
val v = Some(42).getOrElse("FortyTwo")
Here v has type Any. It's very easy to see the problem with such a stupid example but sometimes it's not as obvious and can lead to issues.
While fold:
def fold[B](ifEmpty: ⇒ B)(f: (A) ⇒ B): B
It forces you to return the same type for both branches.
scala> Some(42).fold("fortyTwo")(v => v)
<console>:8: error: type mismatch;
found : Int
required: String
Some(42).fold("fortyTwo")(v => v)
Pattern matching is :
slightly more efficient
not anal about subtypes (in this case #rarry had to add a type hint)
easier to read
endorsed by Martin Oderksy: https://stackoverflow.com/a/5332657/578101
I would go for this:
myOptionInstance.fold(Nil: List[String])(...)