On Scala 2.11.8:
private def safeMax[A](xs: List[A])
(implicit ev: Ordering[A]): Option[A] = xs match {
case ys#(_ :: _) => Some(ys.min)
case Nil => None
}
// Exiting paste mode, now interpreting.
<console>:12: error: No implicit Ordering defined for ?A1.
case ys#(_ :: _) => Some(ys.min)
^
Since ys has type List[A], as I understand, then why does this compile-time error occur?
Note that I could fix it by replace ys.min with xs.min, but I'm still curious.
Related
Scala 3 provides polymorphic functions and Tuples similar to shapeless HList:
scala> 1 *: "foo" *: Tuple()
val res0: (Int, String) = (1,foo)
scala> val f: ([T] => T => Option[T]) = [T] => (v: T) => Some(v)
val f: PolyFunction{apply: [T](x$1: T): Option[T]} = <function1>
scala> res0.map(f)
val res1: Option[Int] *: Option[String] *: EmptyTuple = (Some(1),Some(foo))
How could we reimplement the following shapeless example using Scala 3 functionality?
import poly._
object choose extends (Set ~> Option) {
def apply[T](s : Set[T]) = s.headOption
}
scala> val sets = Set(1) :: Set("foo") :: HNil
sets: Set[Int] :: Set[String] :: HNil = Set(1) :: Set(foo) :: HNil
scala> val opts = sets map choose
opts: Option[Int] :: Option[String] :: HNil = Some(1) :: Some(foo) :: HNil
In other words, how could we make something like so compile
scala> val choose: ([T] => Set[T] => Option[T]) = [T] => (s: Set[T]) => s.headOption
val choose: PolyFunction{apply: [T](x$1: Set[T]): Option[T]} = <function1>
scala> val sets = Set(1) *: Set("foo") *: Tuple()
val sets: (Set[Int], Set[String]) = (Set(1),Set(foo))
scala> sets.map(choose)
1 |sets.map(choose)
| ^^^^^^
| Found: (choose : PolyFunction{apply: [T](x$1: Set[T]): Option[T]})
| Required: PolyFunction{apply: [t](x$1: t): Any}
Shapeless map is quite a bit more magical than Scala 3 tuple map, the signature of latter being:
def map[F[_]](f: [t] => (x$1: t) => F[t]): Map[Tuple, F]
Map[Tuple, F] is a special match type that is basically tuple with every argument type wrapped in F[_]. The issue is that shape, t => F[t] that prevents too much fanciness.
Except of course, F can be a match type itself:
type Choose[T] = T match {
case Set[a] => Option[a]
}
def choose[T](t: T): Choose[T] = t match
case set: Set[a] => set.headOption
// messy, but it works
#main def run =
val sets = Set(1) *: Set("foo") *: Tuple()
println(sets.map([T] => (t: T) => choose(t)))
There's currently an issue that compiler won't infer polymorphic function from methods. Match types aren't fully type-safe either, e.g. doing choose("string") will compile but throw a MatchError. I've also ran into problems with inference of a match type from polymorphic function value, hence the usage of def method.
Something like:
def cast[T](o: Any): Option[T] = o match {
case v: T => Some(v)
case _ => None
}
or:
def cast[T](c: Class[T], o: Any): Option[T] = o match {
case v: T => Some(v)
case _ => None
}
Is this a good idea? Is there a standard library equivalent?
Why do I get and how do I resolve the following Scala compiler warning:
Warning:(7, 13) abstract type pattern T is unchecked since it is eliminated by erasure
case v: T => Some(v)
Use class tag. Type information gets lost during runtime.So, you need provide type information which can be done using class tag.
import scala.reflect.ClassTag
def cast[T: ClassTag](o: Any): Option[T] = o match {
case v: T => Some(v)
case _ => None
}
Scala REPL
scala> cast[String]("hello")
res2: Option[String] = Some(hello)
scala> cast[Int]("scala")
res3: Option[Int] = None
I am using a Java library which returns an object of type Object. Now I want to pattern match and get the appropriate type. I expect it to be a Java Map. So, I tried using this:
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.collection.JavaConverters._
val any: Any = new java.util.HashMap[Object, Object]
Option(any).flatMap {
case x: java.util.Map[_, _] => Some(x.asScala.toMap)
case x: Map[_, _] => Some(x)
case _ => None
}
// Exiting paste mode, now interpreting.
<console>:17: error: no type parameters for method flatMap: (f: Any => Option[B])Option[B] exist so that it can be applied to arguments (Any => Option[scala.collection.immutable.Map[_,Any]] forSome { type _ })
--- because ---
argument expression's type is not compatible with formal parameter type;
found : Any => Option[scala.collection.immutable.Map[_,Any]] forSome { type _ }
required: Any => Option[?B]
Option(any).flatMap {
^
<console>:17: error: type mismatch;
found : Any => Option[scala.collection.immutable.Map[_,Any]] forSome { type _ }
required: Any => Option[B]
Option(any).flatMap {
^
Not sure what I am doing wrong here.
The below works. The compiler doesn't have the enough information to derive the type here since we are using existential types for our Maps in the pattern matching. This is because unlike Java Map is not a type in scala but Map[T,U] is
Option(any).flatMap[Any]({
case x: java.util.Map[_, _] => Some(x.asScala.toMap)
case x: Map[_, _] => Some(x)
case _ => None
})
If we dont use existential type as shown below, we would be able to use the flatMap without the explicit type parameter specified
scala> Option(any).flatMap({
| case x: java.util.Map[Int, Int] #unchecked => Some(x.asScala.toMap) // using Int as example to create a fully qualified type of Map
| case x: Map[Int, Int] #unchecked => Some(x) // using Int as example to create a fully qualified type of Map
| case _ => None
| })
res5: Option[scala.collection.immutable.Map[Int,Int]] = Some(Map())
This question already has answers here:
Why doesn't passing Nil to foldLeft work?
(2 answers)
Closed 8 years ago.
So I've got my version of List class in scala:
sealed trait List[+A] {
(...)
}
case object Nil extends List[Nothing]
case class Cons[+A](_head: A, _tail: List[A]) extends List[A]
now I'm trying to write reverse in terms of my foldLeft which is the following:
#annotation.tailrec
def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
case Nil => z
case Cons(x,xs) => foldLeft(xs,f(z,x))(f)
}
here is the problematic part:
def revers[A](l:List[A]) : List[A] = foldLeft(l,Nil)((b,a) => Cons(a,b))
that gives me type errors:
[error] found : datastructures.Cons[A]
[error] required: datastructures.Nil.type
[error] foldLeft(l,Nil)((b,a) => Cons(a,b))
I've could solve this by not using Nil at all like this:
def revers[A](l:List[A]) : List[A] = l match {
case Nil => Nil
case Cons(x,xs) => foldLeft(xs,Cons(x,Nil))((b,a) => Cons(a,b))
}
but still I would like to know how can I pass this?
You can specify the type :
scala> def revers[A](l:List[A]) : List[A] =
foldLeft(l,Nil:List[A])((b,a) => Cons(a,b))
revers: [A](l: List[A])List[A]
scala> val l:List[Int] = Cons(1,Cons(2,Cons(3,Nil)))
l: List[Int] = Cons(1,Cons(2,Cons(3,Nil)))
scala> revers(l)
res0: List[Int] = Cons(3,Cons(2,Cons(1,Nil)))
Scala's type inference works one block at a time, so when you write foldLeft(l,Nil), it expects the return type to be Nil. The function you passed ((b,a) => Cons(a,b))) has a return type of Cons[A], leading to the error. Specifying that Nil:List[A] in foldLeft(l, Nil) prevents it. See stackoverflow.com/questions/9785655/… for better explanations.
See the following code:
def createOption[T: TypeTag](referentialData: Any) : Option[T] = {
Option(referentialData) match {
case Some(camelMessage: CamelMessage) => {
Option(camelMessage.body) match {
case Some(option: T) => Some(option)
case _ => None
}
}
case _ => None
}
}
Basically I am looking to return an Option[T] if camelMessage.body is non-null and of type T.
The uses of Option(referentialData) is effectively referentialData != null
Likewise for Option(camelMessage.body)
How do I use the TypeTag to determine if camelMessage.body is of type T.
(I know this can be re-written to not use TypeTags and Options but I want to learn how to use TypeTags so please no suggestions to re-write, thanks!)
Edit
I tried a new approach as could not find a solution for the above, but could not get this one to work either:
def createOption[T](referentialData: Any) : Option[T] = {
Option(referentialData) match {
case Some(option) => Try(option.asInstanceOf[T]).toOption
case _ => None
}
}
When I invoke this using createOption[Long]("test") I was presuming to get a None back, but instead I got a Some(String)
Where am I going wrong here?
This is a duplicate of this one.
But you want to try it with ClassTag to show the limitation:
scala> def f[A: ClassTag](x: Any): Option[A] = x match {
| case y: A => println("OK"); Some(y) ; case _ => println("Nope"); None }
f: [A](x: Any)(implicit evidence$1: scala.reflect.ClassTag[A])Option[A]
scala> f[String]("foo")
OK
res0: Option[String] = Some(foo)
scala> f[Long](2L)
Nope
res1: Option[Long] = None
scala> f[java.lang.Long](new java.lang.Long(2L))
OK
res2: Option[Long] = Some(2)
scala> def f[A: TypeTag](x: Any): Option[A] = Option(x) match {
| case Some(y: A) => println("OK"); Some(y) ; case _ => println("Nope"); None }
<console>:51: warning: abstract type pattern A is unchecked since it is eliminated by erasure
case Some(y: A) => println("OK"); Some(y) ; case _ => println("Nope"); None }
^
f: [A](x: Any)(implicit evidence$1: reflect.runtime.universe.TypeTag[A])Option[A]