how to use > < <= >= as functions? - scala

I need define some case classes like the following one:
case class Gt(key: String, value: Any) extends Expression {
def evalute[V, E](f: String => Any) = {
def compare(v: Any): Boolean = {
v match {
case x: Number => x.doubleValue > value.asInstanceOf[Number].doubleValue
case x: Array[_] => x.forall(a => compare(a))
case x => x.toString > value.toString
}
}
compare(f(key))
}
}
i don't like repeat that for > < >= and <=
i also tried this:
trait Expression {
def evalute[V, E](f: String => Any) = true
def compare(v: Any, value: Any, cp: (Ordered[_], Ordered[_]) => Boolean): Boolean = {
v match {
case x: Number => cp(x.doubleValue, value.asInstanceOf[Number].doubleValue)
case x: Array[_] => x.forall(a => compare(a, value, cp))
case x => cp(x.toString, value.toString)
}
}
}
case class Gt(key: String, value: Any) extends Expression {
def evalute[V, E](f: String => Any) = {
compare(f(key), value, ((a, b) => a > b))
}
}
but that not working :(
error: could not find implicit value for parameter ord: scala.math.Ordering[scala.math.Ordered[_ >: _$1 with _$2]]
compare(f(key), value, ((a, b) => a > b))
Is there a way that pass a operator as a function in scala?

(a, b) => a > b works fine. Your problem is with the types.
What are V and E in evalute[V, E] supposed to be?
You pass it (a, b) => a > b as the parameter cp: (Ordered[_], Ordered[_]) => Boolean. So you have a: Ordered[_] and b: Ordered[_]. Which is the same as a: Ordered[X] forSome {type X} and b: Ordered[Y] forSome {type Y}. With these types, a > b doesn't make sense.

In Scala, those are not operators, but methods. You can lift any method to a function by putting an underscore after it. e.g.
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_21).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val f: (Int => Boolean) = 1 <= _
f: (Int) => Boolean = <function1>
scala> (0 to 2).map(f)
res0: scala.collection.immutable.IndexedSeq[Boolean] = Vector(false, true, true)

I'm not familiar with Scala, it does seem to have support for anonymous functions/lambdas: http://www.scala-lang.org/node/133

Related

Getting around invariant result type in State

I would like to define a State that builds a concrete subtype of a trait, as per decodeFoo:
sealed trait Foo
case class Bar(s: String) extends Foo
case class Baz(i: Int) extends Foo
val int: State[Seq[Byte], Int] = State[Seq[Byte], Int] {
case bs if bs.length >= 4 =>
bs.drop(4) -> ByteBuffer.wrap(bs.take(4).toArray).getInt
case _ => sys.error(s"Insufficient data remains to parse int")
}
def bytes(len: Int): State[Seq[Byte], Seq[Byte]] = State[Seq[Byte], Seq[Byte]] {
case bs if bs.length >= len => bs.drop(len) -> bs.take(len)
case _ => sys.error(s"Insufficient data remains to parse $len bytes")
}
val bytes: State[Seq[Byte], Seq[Byte]] = for {
len <- int
bs <- bytes(len)
} yield bs
val string: State[Seq[Byte], String] = bytes.map(_.toArray).map(new String(_, Charset.forName("UTF-8")))
val decodeBar: State[Seq[Byte], Bar] = string.map(Bar)
val decodeBaz: State[Seq[Byte], Baz] = int.map(Baz)
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => decodeBar
case 1 => decodeBaz
}
This will not compile as State is defined in cats as type State[S, A] and the compiler responds:
Error:(36, 15) type mismatch;
found : cats.data.State[Seq[Byte],FooBarBaz.this.Bar]
(which expands to) cats.data.IndexedStateT[cats.Eval,Seq[Byte],Seq[Byte],FooBarBaz.this.Bar]
required: cats.data.IndexedStateT[cats.Eval,Seq[Byte],Seq[Byte],FooBarBaz.this.Foo]
Note: FooBarBaz.this.Bar <: FooBarBaz.this.Foo, but class IndexedStateT is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
case 0 => decodeBar
I can work around this by widening the definitions of decodeBar & decodeBaz to be of type State[Seq[Byte], Foo]. Is that the best way forward? Or can I take a different approach that avoids widening these types?
Functor.widen
Functor.widen should do the trick. Full compilable example (with kind-projector):
import cats.data.State
import cats.Functor
object FunctorWidenExample {
locally {
sealed trait A
case class B() extends A
val s: State[Unit, B] = State.pure(new B())
val t: State[Unit, A] = Functor[State[Unit, ?]].widen[B, A](s)
}
}
in your case, it would be something like:
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => Functor[State[Seq[Byte], ?]].widen[Bar, Foo](decodeBar)
case 1 => Functor[State[Seq[Byte], ?]].widen[Bar, Foo](decodeBaz)
}
Other possible work-arounds
(not really necessary, just to demonstrate the syntax that might be less known):
Explicit type ascriptions:
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => decodeBar.map(x => (x: Foo))
case 1 => decodeBaz.map(x => (x: Foo))
}
Using <:< as method (those things actually do have a meaningful apply):
val decodeFoo: State[Seq[Byte], Foo] = int.flatMap {
case 0 => decodeBar.map(implicitly: Bar <:< Foo)
case 1 => decodeBaz.map(implicitly: Baz <:< Foo)
}

Scala: match case over generic functions

Is it possible to do match-case over functions?
I want to define a behavior for different types of functions. Say I have the following possibilities:
f: T => Int
f: T => String
f: T => Lis[Int]
f: T => Boolean
f: T => Double
...
and for each of these options I have a function; for example for Int output:
def doThisForInt(f: T => Int) = { ... }
and this for Boolean output:
`
def doThisForBoolean(f: T => Boolean) = { ... }
So now suppose a function definition is given: val f = (input: T) => true. We should choose the corresponding case to f: T => Boolean.
Note that all these functions differ in the output type. Alternatively, given f can I get the output type of this function?
TypeTags are what you are looking for:
import scala.reflect.runtime.universe._
def doThisForInt(f: T => Int) = ???
def printType[R: TypeTag](f: T => R) = typeOf[R] match {
case t if t =:= typeOf[Int] =>
val toInt: (T) => Int = f.asInstanceOf[T => Int]
doThisForInt(toInt)
case t if t =:= typeOf[Double] =>
// ...
case t if t =:= typeOf[List[Int]] =>
// ...
}
printType((x: T) => 1) // int
printType((x: T) => 2.0) // double
printType((x: T) => List(2)) // list
As you can see, it is possible, but not very elegant and against good practices.
Chains of instanceOf checks can often be replaced with virtual methods (see the example) and the result type of function can possibly be a type parameter. It's hard to give more advice without knowing more context for your use case.

How can I compose generic methods in Scala?

I'm learning Scala and have the following toy code:
object M {
def isSorted[X](xs: Array[X], compare: (X, X) => Boolean): Boolean =
xs.dropRight(1).zip(xs.drop(1)).forall(Function.tupled(compare))
def curry[A,B,C](f: (A, B) => C) : A => (B => C) =
(a) => (b) => f(a, b)
}
My goal is to call it like:
M.curry(M.isSorted)(Array(1,2,3))((a, b) => a < b)
But I receive the error:
scala> M.curry(M.isSorted)(Array(1,2,3))
<console>:8: error: type mismatch;
found : Int(1)
required: Nothing
M.curry(M.isSorted)(Array(1,2,3))
Let's back up and look at the type of the curried function:
scala> M.curry(M.isSorted)
res2: Array[Nothing] => (((Nothing, Nothing) => Boolean) => Boolean) = <function1>
That's no good. It wants an Array[Nothing] but there can be no instances of Nothing.
I understand at some point I will need to introduce a constraint so the compiler can prove that the expression a < b is allowable; that is, that a and b are Ordered. But I don't know where I would put the constraint. curry is perfectly generic; the constraint doesn't belong there. isSorted knows nothing about the implementation of compare, so it doesn't belong there either.
The closest I've gotten to having it working is with def isSorted[X >: Any]
scala> M.curry(M.isSorted)(Array(1,2,3))((a, b) => a < b)
<console>:8: error: value < is not a member of Any
M.curry(M.isSorted)(Array(1,2,3))((a, b) => a < b)
^
scala> M.curry(M.isSorted)(Array(1,2,3))((a: Int, b: Int) => a < b)
<console>:8: error: type mismatch;
found : (Int, Int) => Boolean
required: (Any, Any) => Boolean
M.curry(M.isSorted)(Array(1,2,3))((a: Int, b: Int) => a < b)
^
How can I get this working?
object M {
def isSorted[X](xs: Array[X], compare: (X, X) => Boolean): Boolean =
xs.dropRight(1).zip(xs.drop(1)).forall(Function.tupled(compare))
def curry[A,B,C](f: (A, B) => C) : A => (B => C) =
(a) => (b) => f(a, b)
}
Well... I don't think this is the best way to define these functions but in this case, since these are generic functions so you need to provide them with a type when calling.
As #dk14 has pointed out in his comment... M.sorted can not get type info because Scala lacks support for polymorphic lambdas.... which simply means no generics in anonymous functions.
So you need to do this for this particular case.
M.curry( M.isSorted[Int] )( Array(1,2,3) ) ( (a , b) => a < b )

How to pattern-match against every numeric class in one case?

Suppose I have
def foo(x: Any) = x match {
case s: String => println(0)
case i: Int => println(1)
case l: Long => println(2)
//...
}
Is there any way to make something like the following?
def foo(x: Any) = x match {
case s: String => println(0)
case i: Numeric => println("Numeric")
}
You could match against the Number interface:
def foo(x: Any) = x match {
case s: String => println(0)
case i: java.lang.Number => println("Numeric")
}
You could try this:
def foo[A](x: A)(implicit num: Numeric[A] = null) = Option(num) match {
case Some(num) => println("Numeric: " + x.getClass.getName)
case None => println(0)
}
Then this
foo(1)
foo(2.0)
foo(BigDecimal(3))
foo('c')
foo("no")
will print
Numeric: java.lang.Integer
Numeric: java.lang.Double
Numeric: scala.math.BigDecimal
Numeric: java.lang.Character
0
Note that obtaining a null implicit parameter would not mean that no such implicit exist, but just that none was found at compile time in the search scope for implicits.

Method to check reference equality for Any type

I'm trying to make a method that will match on reference equality for any type, including primitives. How best to do this?
eq is only defined on AnyRef. If we try
def refEquals[A <% AnyRef, B <% AnyRef](a: A, b: B) = a eq b
then on running refEquals(1,2) we find there are implicit methods in Predef including int2IntegerConflict to scupper such conversions.
I tried this:
def refEquals(a: Any, b: Any) = a match {
case x: AnyRef => b match {
case y: AnyRef => x eq y
case _ => false
}
case x: Any => b match {
case y: AnyRef => false
case y: Any => x == y
}
}
But this doesn't work (refEquals(1.0, 1.0) gives false) for reasons given by Rex Kerr here: Strange pattern matching behaviour with AnyRef
So how do we implement such a method?
edit: should have said "reference equality for reference types, or value equality for primitive types".
edit: here's the method using the idea from Rex's answer, for anyone who needs this and doesn't like typing:
def refEquals(a: Any, b: Any) = a match {
case x: Boolean if b.isInstanceOf[Boolean] => x == b
case x: Byte if b.isInstanceOf[Byte] => x == b
case x: Short if b.isInstanceOf[Short] => x == b
case x: Char if b.isInstanceOf[Char] => x == b
case x: Int if b.isInstanceOf[Int] => x == b
case x: Float if b.isInstanceOf[Float] => x == b
case x: Double if b.isInstanceOf[Double] => x == b
case x: Long if b.isInstanceOf[Long] => x == b
case _ => a.asInstanceOf[AnyRef] eq b.asInstanceOf[AnyRef]
}
Reference equality is undefined for primitive types because they are not references. The only notion of equality in that case is value equality.
However, if you want your code to work both with primitives and reference types, you can either use '==' and make sure you pass objects that don't redefine 'equals', or define your own equality object and pass it around. You could probably use 'scala.math.Equiv[T]'.
def myRefEquals[A](x: A, y: A)(implicit eq: Equiv[A]) {
eq.equiv(x, y)
}
implicit def anyRefHasRefEquality[A <: AnyRef] = new Equiv[A] {
def equiv(x: A, y: A) = x eq y
}
implicit def anyValHasUserEquality[A <: AnyVal] = new Equiv[A] {
def equiv(x: A, y: A) = x == y
}
println(myRefEquals(Some(1), Some(1)))
This assumes you want the both objects to have the same type.
You catch all the primitives first, then fall through to eq:
def refEquals(a: Any, b: Any) = a match {
case x: Boolean => b match {
case y: Boolean => x==y
case _ => false
}
case x: Byte =>
...
case _ => a.asInstanceOf[AnyRef] eq b.asInstanceOf[AnyRef]
}