Avoid explicit type parameters on map operations - scala

I have a Span[A] data type that tracks a minimum and maximum value of type A. Because of this, I require A to have a Scalaz Order instance. Here's what the implementation looks like:
trait Span[A] {
val min: A
val max: A
}
object Span {
def apply[A : Order](id: A): Span[A] = new Span[A] {
override val min = id
override val max = id
}
def apply[A : Order](a: A, b: A): Span[A] = {
val swap = implicitly[Order[A]].greaterThan(a, b)
new Span[A] {
override val min = if (swap) b else a
override val max = if (swap) a else b
}
}
implicit def orderSpanSemigroup[A : Order]: Semigroup[Span[A]] = new Semigroup[Span[A]] {
override def append(f1: Span[A], f2: => Span[A]): Span[A] = {
val ord = implicitly[Order[A]]
Span(ord.min(f1.min, f2.min), ord.max(f1.max, f2.max))
}
}
}
The apply method seems to work as expected, as I can do this:
val a = Span(1) // or Span.apply(1)
It breaks down if I try to map over this value using a functor, for example, an Option[Int]:
val b = 1.some map Span.apply
// could not find implicit value for evidence parameter of type scalaz.Order[A]
However, I can fix the error by using an explicit type parameter:
val c = 1.some map Span.apply[Int]
Why is this happening? Is there a way to avoid this explicit type parameter? I wonder if it's related to this issue as I originally ran into the problem while trying to use my own implicit Order instance. Of course, it's also failing on Int inputs so maybe it's just a limitation of parameterized methods.

Related

How to reflect concrete types that corresponds to the type parameters of an abstraction type in Scala?

Suppose we have a generic type (for example, Seq[E]) and a concrete subtype (for example, Seq[Int]). How can we extract concrete type that corresponds to the type parameters of the abstraction type. In other words, how can we know E -> Int.
Below is a minimal code example that tests for the desired behavior. The extractTypeBinding function would perform the transformation in question.
import scala.reflect.runtime.{universe => ru}
class MyFuncs
object MyFuncs {
def fn1[E](s: Seq[E]): E = ???
def fn2[K, V](m: Map[K, V]): Int = ???
}
object Scratch {
def extractTypeBinding(genType: ru.Type, typeParam: ru.Type)(concreteType: ru.Type): ru.Type = ???
def getArgTypes(methodSymbol: ru.MethodSymbol): Seq[ru.Type] =
methodSymbol.paramLists.headOption.getOrElse(Nil).map(_.typeSignature)
def main(a: Array[String]): Unit = {
// Grab the argument types of our methods.
val funcsType = ru.typeOf[MyFuncs].companion
val fn1ArgTypes = getArgTypes(funcsType.member(ru.TermName("fn1")).asMethod)
val fn2ArgTypes = getArgTypes(funcsType.member(ru.TermName("fn2")).asMethod)
val genericSeq = fn1ArgTypes.head // Seq[E]
val genericMap = fn2ArgTypes.head // Map[K, V]
// Create an extractor for the `E` in `Seq[E]`.
val seqElExtractor = extractTypeBinding(genericSeq, genericSeq.typeArgs.head) _
// Extractor for the `K` in `Map[K,V]`
val mapKeyExtractor = extractTypeBinding(genericMap, genericMap.typeArgs.head) _
// Extractor for the `V` in `Map[K,V]`
val mapValueExtractor = extractTypeBinding(genericMap, genericMap.typeArgs(1)) _
println(seqElExtractor(ru.typeOf[Seq[Int]])) // should be Int
println(seqElExtractor(ru.typeOf[Seq[Map[String, Double]]])) // should be Map[String, Double]
println(mapKeyExtractor(ru.typeOf[Map[String, Double]])) // should be String
println(mapKeyExtractor(ru.typeOf[Map[Int, Boolean]])) // should be Int
println(mapValueExtractor(ru.typeOf[Map[String, Double]])) // should be Double
println(mapValueExtractor(ru.typeOf[Map[Int, Boolean]])) // should be Boolean
}
}
Based on the docstrings, it seems like asSeenFrom should be the key to implementing extractTypeBinding. I tried the below implementation, but it returned the type parameter unchanged.
def extractTypeBinding(genType: ru.Type, typeParam: ru.Type)(concreteType: ru.Type): ru.Type =
typeParam.asSeenFrom(concreteType, genType.typeSymbol.asClass)
...
println(seqElExtractor(ru.typeOf[Seq[Int]])) // E
println(seqElExtractor(ru.typeOf[Seq[Map[String, Double]]])) // E
If asSeenFrom is the correct approach, what would the correct incantation be?
If not, then how should this be done?
The simplest solution came from the helpful prodding by Dmytro Mitin in the comments.
I had a couple misunderstandings about .typeArgs that were cleared up with some additional experimentation.
It returns all type arguments, not just the abstract ones.
It only returns the "top level" type arguments of the type you call it on. In other words, Map[A, Map[B, C]] only has 2 type args (A and Map[B, C])
Both of those seem very intuitive now, but I initially made some foolish assumptions. Below is a modified version of my test that more clearly achieves my original intent.
class MyFuncs
object MyFuncs {
def fn1[E](s: Seq[E]): E = ???
def fn2[K, V](m: Map[K, V]): Int = ???
}
object Scratch {
def typeArgBindings(genericType: ru.Type, concreteType: ru.Type): Map[ru.Type, ru.Type] =
// #todo consider validating both have the same base type.
genericType.typeArgs.zip(concreteType.typeArgs).toMap
def getArgTypes(methodSymbol: ru.MethodSymbol): Seq[ru.Type] =
methodSymbol.paramLists.headOption.getOrElse(Nil).map(_.typeSignature)
def main(a: Array[String]): Unit = {
// Grab the argument types of our methods.
val funcsType = ru.typeOf[MyFuncs].companion
val fn1ArgTypes = getArgTypes(funcsType.member(ru.TermName("fn1")).asMethod)
val fn2ArgTypes = getArgTypes(funcsType.member(ru.TermName("fn2")).asMethod)
val genericSeq = fn1ArgTypes.head // Seq[E]
val genericMap = fn2ArgTypes.head // Map[K, V]
println(typeArgBindings(genericSeq, ru.typeOf[Seq[Int]])) // Map(E -> Int)
println(typeArgBindings(genericSeq, ru.typeOf[Seq[Map[String, Double]]])) // Map(E -> Map[String,Double])
println(typeArgBindings(genericMap, ru.typeOf[Map[String, Double]])) // Map(K -> String, V -> Double)
println(typeArgBindings(genericMap, ru.typeOf[Map[Int, Boolean]])) // Map(K -> Int, V -> Boolean)
}
}

How to get structural union types in Scala?

I'm not sure if "structural union types" is the right terminology, but I'm trying to get the following duck-typing behavior in Scala.
Suppose I have some container class Container with methods to get objects of type A and B:
class Container {
def getA: A
def getB: B
}
A and B both have a commontIntField attribute, but they also have some non-shared methods:
class A {
val commonIntField: Int
def getAStringField1: String
def getAStringField2: String
}
class B {
val commonIntField: Int
def getBStringField: String
}
Now suppose I want to define the following three functions, which all look very similar to each other:
def f1(c: Container) = {
val a = c.getA
(0 to a.commonIntField) foreach { println(a.getAStringField1) }
}
def f2(c: Container) = {
val a = c.getA
(0 to a.commonIntField) foreach { println(a.getAStringField2) }
}
def f2(c: Container) = {
val b = c.getB
(0 to b.commonIntField) foreach { println(a.getBStringField) }
}
What I'm looking for is some way to DRY this up, e.g. something like this:
def f(getAOrB, getStringField)(c: Container) = {
val aOrB = c.getAOrB
(0 to aOrB.commonIntField) foreach { println(aOrB.getStringField) }
}
val f1 = f(_.getA, _.getAStringField1)
val f2 = f(_.getA, _.getAStringField2)
val f3 = f(_.getB, _.getBStringField)
My question: What type parameters can I use for f to get this to compile? (Assume here that I can't change the definitions of Container, A, or B, although I can of course define auxiliary types if I need to.)
You should add a type parameter to f and constrain it.
So we firstly add parameter and refactor it correspondingly:
def f[T](tGetter: Container => T, getStringField: T => String)(c: Container) = {
val t: T = tGetter(c)
val intField = getIntField(t)
(0 to intField) foreach { println(stringGetter(t)) }
}
And there is a problem - how can we define the way how we fetch T from a Container?
Simpler way - just add tGetter: Container => T as the first parameter. This is additional param but it is simple, and it will help you in auto type deriving of the type parameter.
def f[T](tGetter: Container => T, getStringField: T => String)(c: Container) = {
val t: T = tGetter(c)
val intField: Int = ??? // getIntField(t)
(0 to intField).foreach { _ => println(getStringField(t)) }
}
// val f1 = f(_.getA, _.getAStringField1) // the old one
val f1 = f[A](_.getA, _.getAStringField1)(_)
// val f2 = f(_.getA, _.getAStringField2)
val f2 = f[A](_.getA, _.getAStringField2)(_)
// val f3 = f(_.getB, _.getBStringField)
val f3 = f[B](_.getB, _.getBStringField)(_)
But there is a problem - how can we get the int field?
We have a few ways.
1. Structural typing
You simply express desired structural type like this { def commonIntField: Int } and write upper type bound for T:
def f[T <: { def commonIntField: Int }](tGetter: Container => T, getStringField: T => String)(c: Container) = {
Or nicer variation with type alias:
type HaveIntField = { def commonIntField: Int }
def f[T <: HaveIntField](tGetter: Container => T, getStringField: T => String)(c: Container) = {
But structural typing is considered bad practice because it uses reflection and not very safe.
2. Type classes
You need to express that the T would have a way of getting the int field without a common supertype. You can add this functionality with type class pattern in scala. You can easily google guides on how to write type classes. I just will demonstrate the final result.
You would add a typeclass that says that your type has a way of getting the int field.
trait HaveIntField[X] {
def getIntField(x: X): Int
}
Then you create instances of that type class for every class that you want to support in such functionality.
object HaveIntField {
implicit val haveIntField_A_Instance: HaveIntField[A] = new HaveIntField[A] {
def getIntField(a: A): Int = a.commonIntField
}
implicit val haveIntField_A_Instance: HaveIntField[A] = new HaveIntField[A] {
def getIntField(a: A): Int = a.commonIntField
}
}
And then finally you add the context bound on T.
def f[T: HaveIntField](tGetter: Container => T, getStringField: T => String)(c: Container) = {
val t: T = tGetter(c)
val intField = implicitly[HaveIntField[T]].getIntField(t)
0 to intField) foreach { println(stringGetter(t)) }
}
This looks a little bit nasty and overwhelming in Scala 2, but it is a cool concept from FP/Haskell. And it would be very smooth in the upcoming Scala 3.

Scala: function as a parameter to map()

How to use the map method in the Iterable trait in the example below?
As I understand this method will return a function which I have to call to execute internal logic.
trait Container[E] {
def += (e: E): Unit
}
trait Iterable[E, C[X] <: Container[X]]
{
def iterator(): Iterator[E]
def build[F](): C[F]
def map[F](f : (E) => F) : C[F] = {
val res = build[F]()
val iter = iterator()
while (iter.hasNext) res += f(iter.next())
res
}
}
class Buffer[T] extends Container[T]
{
val list = scala.collection.mutable.ListBuffer.empty[T]
def Children = list
def += (e: T): Unit = list += e
}
class Range(val low: Int, val high: Int) extends Iterable[Int, Buffer] {
def iterator() = new Iterator[Int]
{
private var i = low
def hasNext = i <= high
def next() = { i += 1; i - 1 }
}
def build[F]() = new Buffer[F]
}
val range = new Range(1, 3)
var list = range.map[String](_)
The method in question has the following signature:
trait Iterable[E, C[X] <: Container[X]] {
def map[F](f : (E) => F) : C[F]
// ...
}
First, let's look at the type of f argument. The signature (E) => F says that f is a function which takes a single argument of type E and returns a value of type F. Any function (or method) with this signature can be passed to map() as argument. See also Scala documentation.
Another important thing to understand is that the map function is generic with type parameter F. Value for this type parameter can either be specified manually or inferred by the compiler from the argument passed to map:
new Range(1,2).map[String](_.toString) // F is String
// new Range(1,2).map[Int](_.toString) // F is Int, compilation will fail
val mapFunction: Int => String = _.toString
new Range(1,2).map(mapFunction) // mapFunction is a function from Int to String,
// the compiler infers F is String
Basically, e.g. with Range, you can pass to the map() function any function which takes a single Int parameter (because Range binds E to Int) and returns anything (except for Unit). A few more examples:
val r = Range(1,2)
val v1: Buffer[String] = r.map(_.toString)
val v2: Buffer[Int] = r.map(i => i + 1)
val v3: Buffer[Double] = r.map(Int.int2double)
val i: Int = 1
val v4: Buffer[Int] = r.map(i.max)
As you can see, map() returns type Buffer[F] because that's what Range binds to the C[X] type parameter.
As #vitalii noted, the question is not related to higher-kinded types. For more information about those, check out other questions or blogs.
new Range(2,5).map(_.toString)

Hoes do Spray Parameters work?

I'm trying to wrap my head around how Spray has implemented their Directives, and in particular the Parameter extraction DSL.
I understand the magnet pattern (barely) but am stuck on how the ParamDefMagnet and ParamDefMagnet2 work together.
def parameter(pdm: ParamDefMagnet): pdm.Out = pdm()
trait ParamDefMagnet {
type Out
def apply(): Out
}
trait ParamDefMagnet2[T] {
type Out
def apply(value: T): Out
}
type ParamDefMagnetAux[A, B] = ParamDefMagnet2[A] { type Out = B }
def ParamDefMagnetAux[A, B](f: A ⇒ B) = new ParamDefMagnet2[A] { type Out = B; def apply(value: A) = f(value) }
I'm trying to work out how a ParamDefManget2 is implicitly converted to a ParamDefMagnet by the the below implicit method.
object ParamDefMagnet {
implicit def apply[T](value: T)(implicit pdm2: ParamDefMagnet2[T]) = new ParamDefMagnet {
type Out = pdm2.Out
def apply() = pdm2(value)
}
}
If i call parameter("name"), how is "name" implicitly converted to a ParamDefMagnet? And if it converts it to a ParamDefMagnet2 first, then where does value: T come from in order to convert it to a ParamDefMagnet?
So after digging around with examples, I think i've finally got to the bottom of how the parameter function works:
def parameter(pdm: ParamDefMagnet): pdm.Out = pdm()
An example for extracting a parameter of type String:
val p: Directive1[String] = parameter("name")
// we can then apply the function with the extracted name
p { name =>
// stuff
}
Spray uses a bunch of implicit conversions but basically, if you have a String and a String => Directive1[String], you can construct a () => Directive1[String]:
// Our String => Directive1[String]
val pdm2: ParamDefMagnet2[String] { type Out = Directive1[String] } = ParamDefMagnet2.fromString
// Our () => Directive1[String]
val pdm: ParamDefMagnet { type Out = Directive1[String] } = new ParamDefMagnet {
type Out = Directive1[String]
def apply() = pdm2("name")
}
val directive: Directive1[String] = pdm()
// equivalent to:
val directive2: Directive1[String] = parameter("name")
All of this is what constitutes the simple parameter("name") call:
val p: Directive1[String] = parameter("name")
For how a Directive1[String] is applied in a DSL-ey way, see How do directives work in Spray?

How to return optional information from methods?

The general question is how to return additional information from methods, beside the actual result of the computation. But I want, that this information can silently be ignored.
Take for example the method dropWhile on Iterator. The returned result is the mutated iterator. But maybe sometimes I might be interested in the number of elements dropped.
In the case of dropWhile, this information could be generated externally by adding an index to the iterator and calculating the number of dropped steps afterwards. But in general this is not possible.
I simple solution is to return a tuple with the actual result and optional information. But then I need to handle the tuple whenever I call the method - even if I'm not interested in the optional information.
So the question is, whether there is some clever way of gathering such optional information?
Maybe through Option[X => Unit] parameters with call-back functions that default to None? Is there something more clever?
Just my two cents here…
You could declare this:
case class RichResult[+A, +B](val result: A, val info: B)
with an implicit conversion to A:
implicit def unwrapRichResult[A, B](richResult: RichResult[A, B]): A = richResult.result
Then:
def someMethod: RichResult[Int, String] = /* ... */
val richRes = someMethod
val res: Int = someMethod
It's definitely not more clever, but you could just create a method that drops the additional information.
def removeCharWithCount(str: String, x: Char): (String, Int) =
(str.replace(x.toString, ""), str.count(x ==))
// alias that drops the additional return information
def removeChar(str: String, x: Char): String =
removeCharWithCount(str, x)._1
Here is my take (with some edits with a more realistic example):
package info {
trait Info[T] { var data: Option[T] }
object Info {
implicit def makeInfo[T]: Info[T] = new Info[T] {
var data: Option[T] = None
}
}
}
Then suppose your original method (and use case) is implemented like this:
object Test extends App {
def dropCounterIterator[A](iter: Iterator[A]) = new Iterator[A] {
def hasNext = iter.hasNext
def next() = iter.next()
override def dropWhile(p: (A) => Boolean): Iterator[A] = {
var count = 0
var current: Option[A] = None
while (hasNext && p({current = Some(next()); current.get})) { count += 1 }
current match {
case Some(a) => Iterator.single(a) ++ this
case None => Iterator.empty
}
}
}
val i = dropCounterIterator(Iterator.from(1))
val ii = i.dropWhile(_ < 10)
println(ii.next())
}
To provide and get access to the info, the code would be modified only slightly:
import info.Info // line added
object Test extends App {
def dropCounterIterator[A](iter: Iterator[A]) = new Iterator[A] {
def hasNext = iter.hasNext
def next() = iter.next()
// note overloaded variant because of extra parameter list, not overriden
def dropWhile(p: (A) => Boolean)(implicit info: Info[Int]): Iterator[A] = {
var count = 0
var current: Option[A] = None
while (hasNext && p({current = Some(next()); current.get})) { count += 1 }
info.data = Some(count) // line added here
current match {
case Some(a) => Iterator.single(a) ++ this
case None => Iterator.empty
}
}
}
val i = dropCounterIterator(Iterator.from(1))
val info = implicitly[Info[Int]] // line added here
val ii = i.dropWhile((x: Int) => x < 10)(info) // line modified
println(ii.next())
println(info.data.get) // line added here
}
Note that for some reason the type inference is affected and I had to annotate the type of the function passed to dropWhile.
You want dropWhileM with the State monad threading a counter through the computation.