varargs parameter as type parameter? - scala

Is there any way to create something similar to this:
class F[A] {def apply(a: A) = println(a)}
So that I can:
(new F[Int*])(1,2,3)
UPDATE: but otherwise, I want F to accept normal parameters:
(new F[Int])(1)

scala> class F[A] { def apply(a: A*) = a.length }
defined class F
scala> val instance = new F[Int]
instance: F[Int] = F#11a6631
scala> instance(1,2,3,4,5)
res4: Int = 5

Related

Scala: implicitly convert Option to Option of implicit class [duplicate]

I'm trying to write a function which re-uses the implicit conversions which I have for Object A -> Object B when they are wrapped in an Option in a generic way so that Option[A] -> Option[B] conversions also work.
What I've come up with is:
implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
This works when I assign a Some(..) to a value but not when I assign an Option val; see the following console output:
scala> trait T
defined trait T
scala> case class Foo(i: Int) extends T
defined class Foo
scala> case class Bar(i: Int) extends T
defined class Bar
scala> implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
fromFooToBar: (f: Foo)Bar
scala> implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
fromBarToFoo: (b: Bar)Foo
scala> implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] = from.map(conversion(_))
fromOptionToOption: [A, B](from: Option[A])(implicit conversion: (A) => B)Option[B]
scala> val foo: Option[Foo] = Some(Bar(1))
foo: Option[Foo] = Some(Foo(1))
// THIS WORKS as expected
scala> val fooOpt = Some(Foo(4))
fooOpt: Some[Foo] = Some(Foo(4))
scala> val barOpt2: Option[Bar] = fooOpt
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
//THIS FAILS.
I don't really see the difference between the first and second conversion. Somehow it doesn't invoke the implicit conversion in the latter. I guess it has something to do with the type system, but I can't see how just yet. Any ideas?
-Albert
(I'm on scala 2.9.1)
Here's clue:
scala> val fooOpt: Option[Bar] = Option(Foo(1))
fooOpt: Option[Bar] = Some(Bar(1))
And another:
scala> implicit def foobar(x: String): Int = augmentString(x).toInt
foobar: (x: String)Int
scala> val y: Option[String] = Option(1)
y: Option[String] = Some(1)
scala> val y: Option[Int] = Option("1")
y: Option[Int] = Some(1)
Looks like a legitimately odd bug. I'd pop open a smaller test case and open an issue (or search for one in JIRA).
As an aside:
You could use some category theory to handle lots of different types of "Option-ish" things.
package object fun {
trait Functor[Container[_]] {
def fmap[A,B](x: Container[A], f: A => B): Container[B]
}
object Functor {
implicit object optionFunctor extends Functor[Option] {
override def fmap[A,B](x: Option[A], f: A => B): Option[B] = x map f
}
// Note: With some CanBuildFrom magic, we can support Traversables here.
}
implicit def liftConversion[F[_], A, B](x: F[A])(implicit f: A => B, functor: Functor[F]): F[B] =
functor.fmap(x,f)
}
That's a bit more advanced, as you're mapping some category theory FP onto the problem, but it's a more general solution to lift implicit conversations into containers as needed. Notice how they chain by using one implicit conversation method that takes a more limited implicit argument.
ALSO, this should make the examples work:
scala> val tmp = Option(Foo(1))
tmp: Option[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
y: Option[Bar] = Some(Bar(1))
And make your usage of Some more dangerous:
scala> val tmp = Some(Foo(1))
tmp: Some[Foo] = Some(Foo(1))
scala> val y: Option[Bar] = tmp
<console>:25: error: could not find implicit value for parameter functor: fun.Functor[Some]
val y: Option[Bar] = tmp
^
That's telling you that variance is critical, and interacts with implicits. My guess is you ran into a very rare, probably hard to fix bug that can be avoided using other techniques.
You might not be aware of it, but there's a flag for that: -Xlog-implicits. And this is what it says:
scala> val barOpt2: Option[Bar] = fooOpt
fromOptionToOption is not a valid implicit value for Some[Foo] => Option[Bar] because:
incompatible: (from: Option[Foo])(implicit conversion: Foo => B)Option[B] does not match expected type Some[Foo] => Option[Bar]
<console>:16: error: type mismatch;
found : Some[Foo]
required: Option[Bar]
val barOpt2: Option[Bar] = fooOpt
^
And there you go -- it doesn't know what type B must be. 0__ mentioned that this problem doesn't happen with invariant collections, and that makes some sense. In invariant collections, B must be exactly Bar, while for covariant collections it could be any subtype of Bar.
So, why does val foo: Option[Foo] = Some(Bar(1)) work? Well, there's a flag for that too... -Ytyper-debug. Not for the weak, however, given the extreme verbosity.
I waddled through anyway, comparing what happens in both cases, and the answer is rather simple... it's not the Option that is being converted in that case, but Bar! Remember, you declared an implicit conversion from Bar => Foo, so it is applying that conversion before passing the result to Some!
It doesn't work because the Scala Language Specification defines view as follows:
Implicit parameters and methods can also define implicit conversions called views. A view from type S to type T is defined by an implicit value which has function type S=>T or (=>S)=>T or by a method convertible to a value of that type.
fromOptionToOption doesn't conform to the three categories since it takes an implicit parameter. Compiler doesn't seem to find converter with both destination and source having generic type.
Defining a view from Option[Foo] to Option[Bar] works as expected.
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
object Main {
implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
// implicit def fromOptionToOption[A, B](from: Option[A])(implicit conversion: (A) => B): Option[B] =
// from.map(conversion(_))
implicit def fromOptionFooToOptionBar(o: Option[Foo]): Option[Bar] = o map { foo => foo }
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt2: Option[Bar] = fooOpt
barOpt2
}
}
println(Main.test)
Running this prints out:
$ scala so.scala
Some(Bar(4))
However, all is not lost. It's not as nice as general Option to Option, but we can do something like anything that can turn into Bar to Option[Bar] by view bound.
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
object Main {
implicit def fromFooToBar(f: Foo):Bar = Bar(f.i)
implicit def fromBarToFoo(b: Bar):Foo = Foo(b.i)
implicit def fromOptionToOptionBar[A <% Bar](from: Option[A]): Option[Bar] =
from map { foo => foo }
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt2: Option[Bar] = fooOpt
barOpt2
}
}
println(Main.test)
Here's another workaround that can be used for general Option to Option but requires extra .convert call:
trait T
case class Foo(i: Int) extends T
case class Bar(i: Int) extends T
case class Converter[A](x: Option[A]) {
def convert[B](implicit ev: Function1[A, B]): Option[B] = x map { a: A => ev(a) }
}
object Main {
implicit def optionToConverter[A](x: Option[A]) = Converter(x)
implicit def fooToBar(x: Foo) = Bar(x.i)
def test(): Option[Bar] = {
val fooOpt = Some(Foo(4))
val barOpt: Option[Bar] = fooOpt.convert
barOpt
}
}
println(Main.test)
Indeed it's a very strange problem. I tried to use another type than Option, and it turns out that the problem is that Option is covariant in its type parameter. This works all:
case class A[B](value: B) // invariant in B
case class X()
case class Y()
implicit def xtoy(x: X): Y = Y()
implicit def ytox(x: Y): X = X()
implicit def movea[U, V](from: A[U])(implicit view: U => V): A[V] = A[V](from.value)
def test(a: A[Y]) = "ok"
test(A(X())) // (1)
val f = A(X())
test(f) // (2)
But if instead I define A as
case class A[+B](value: B) // covariant in B
The case (2) fails. Case (1) always succeeds, because Scala already converts X to Y before wrapping it in an A.
Now that we know the problem source, you need to wait for a type guru to explain why this is actually a problem... The conversion is still valid, you see:
askForY(movea(f)) // succeeds, even with A[+B]
I improved #jseureth answer and added support for Traversable:
trait Mappable[A, B, C[_]] {
def apply(f: A => B): C[B]
}
package object app {
implicit class OptionMappable[A, B, C[X] <: Option[X]](option: C[A]) extends Mappable[A, B, Option] {
override def apply(f: A => B): Option[B] = option.map(f)
}
implicit class TraversableMappable[A, B, C[X] <: Traversable[X]](traversable: C[A])
(implicit cbf: CanBuildFrom[C[A], B, C[B]]) extends Mappable[A, B, C] {
override def apply(f: A => B): C[B] = {
val builder = cbf(traversable)
builder.sizeHint(traversable)
builder ++= traversable.map(f)
builder.result()
}
}
implicit def liftConversion[C[_], A, B](x: C[A])
(implicit f: A => B, m: C[A] => Mappable[A, B, C]): C[B] = m(x)(f)
}
Now you can implicitly convert options and traversables:
implicit def f(i: Int): String = s"$i"
val a: Option[String] = Some(1)
val b: Seq[String] = Seq(1, 2, 3)

Method overloading in implicit class

I'm using a class (that I cannot modify) containing a method which receives a value of type Any as parameter, like the following example:
class Foo(value: Int) {
def +(other: Any): Foo = ???
}
I would like to add a custom implementation for the method +() when it's used with a specific type. I would expect to be able to do something like:
implicit class RichFoo(foo: Foo) {
def +(other: Int): Foo = ???
}
// or
implicit class RichFoo(foo: Foo) {
def +[T <: Bar](other: T): T = ???
}
However, these approaches don't work.
Is it possible to do without extending the original class?
No.
To the compiler, implicit conversions and other rewrite rules (like those around Dynamic) are a "last resort" of sorts. They are only applied if code does not already typecheck as-is. When you do foo + x, the compiler already knows that + takes Any, so it doesn't even try to look for implicits. If you did foo - x, and Foo had no - of the correct type, only then would the compiler search for a conversion.
Instead, you can create a method with a new name, maybe add, that is not present in Foo but is present in RichFoo. This will not, however, protect you from doing foo + 1 instead of foo add 1, since both methods are valid.
implicit class RichFoo(foo: Foo) {
def add(other: Int): Foo = ???
}
You can use a phantom type to track what is convertible.
scala> trait Tagged[B]
defined trait Tagged
scala> type Of[+A, B] = A with Tagged[B]
defined type alias Of
scala> class Tagger[B] { def apply[A](a: A): A Of B = a.asInstanceOf[A Of B] }
defined class Tagger
scala> object tag { def apply[B]: Tagger[B] = new Tagger[B] }
defined object tag
The given thing:
scala> case class C(i: Int) { def +(x: Any): C = C(i + x.toString.toInt) }
defined class C
and a marker trait:
scala> trait CC
defined trait CC
Normally:
scala> C(42) + "17"
res0: C = C(59)
This works:
scala> val cc = tag[CC](C(42))
cc: Of[C,CC] = C(42)
But not this:
scala> val cc = tag[CC](C(42): Any)
java.lang.ClassCastException: C cannot be cast to Tagged
... 29 elided
Maybe this:
scala> val cc = tag[CC](C(42): Serializable)
cc: Of[Serializable,CC] = C(42)
Then:
scala> implicit class XC(v: Serializable Of CC) {
| def +(x: Any): C Of CC = tag[CC] {
| println("OK")
| v.asInstanceOf[C] + x
| }}
defined class XC
Abnormally:
scala> val valueAdded = cc + "17"
OK
valueAdded: Of[C,CC] = C(59)
There's surely a better way to do this:
scala> implicit def untagit(x: Serializable Of CC): C Of CC = tag[CC](x.asInstanceOf[C])
untagit: (x: Of[Serializable,CC])Of[C,CC]
scala> cc.i
res9: Int = 42
because that ruins it:
scala> val res: C = cc + "17"
<console>:18: error: type mismatch;
found : <refinement>.type (with underlying type Of[Serializable,CC])
required: ?{def +(x$1: ? >: String("17")): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method XC of type (v: Of[Serializable,CC])XC
and method untagit of type (x: Of[Serializable,CC])Of[C,CC]
are possible conversion functions from <refinement>.type to ?{def +(x$1: ? >: String("17")): ?}
val res: C = cc + "17"
^
<console>:18: error: value + is not a member of Of[Serializable,CC]
val res: C = cc + "17"
^

How to override 'apply' in a Function with multiple parameter lists?

I'm trying to make an instance of this type of function object:
trait CanGetSiblingDock[S, D]
extends (D => String => S => Option[D])
with this:
implicit val getSiblingDock = new CanGetSiblingDock[Situation, Dock] {
def apply(dock: Dock)(siblingName: String)(sit: Situation): Option[Dock] = ???
}
The compiler objects:
error: object creation impossible, since method apply in trait Function1 of type (v1: FARG.Dock)String => (TestFARGModel4.this.Situation => Option[FARG.Dock]) is not defined
(Note that T1 does not match FARG.Dock)
implicit val getSiblingDock = new CanGetSiblingDock[Situation, Dock] {
^
If I understand this correctly, the compiler is complaining that the first argument of apply is not of type Dock. It appears to me, though, that it is.
Obviously, I'm misunderstanding something somewhere. How do you correctly make an instance of a Function with multiple parameter lists?
Something like:
scala> trait F extends (String => Int => Int)
defined trait F
scala> object X extends F { def apply(s: String): Int => Int = ??? }
defined object X
The type A => B => C is not Function2[A, B, C], for which the apply method would be def apply(a: A, b: B): C. But instead this is Function1[A, Function1[B, C]], like a curried function. If you want a Function2, you would have to write:
trait Foo extends Function2[Int, String, Boolean] {
override def apply(a: Int, b: String): Boolean = ???
}
If now you want multiple parameter lists, you would have to overload apply:
trait Foo extends Function2[Int, String, Boolean] {
override def apply(a: Int, b: String): Boolean = ???
def apply(a: Int)(b: String): Boolean = apply(a, b)
}
This is not possible because after erasure, both methods would look the same on the byte code level.

How to Rewrite Function Using Context Bounds?

Given the following Addable type-class:
scala> trait Addable[A] {
| def add(x: A): A
| }
defined trait Addable
I created an instance for Int:
scala> class AddInt(x: Int) extends Addable[Int] {
| override def add(y: Int) = x + y
| }
defined class AddInt
Then, I created an implicit AddInt:
scala> implicit val addInt: AddInt = new AddInt(10)
addInt: AddInt = AddInt#1f010bf0
Lastly, I defined a generic function, foo:
scala> def foo[A](x: A)(implicit ev: Addable[A]): A = ev.add(x)
foo: [A](x: A)(implicit ev: Addable[A])A
Now, I can call it with the successful implicit resolution of addInt:
scala> foo(10)
res0: Int = 20
How can I define foo using the context bound notation?
example:
def foo[A : Addable]...?
Just define the method like you do in your own example:
def foo[A : Addable](x: A) = implicitly[Addable[A]].add(x)

Is providing explicitly the context bound possible in Scala?

In the following code:
def sum[A: Monoid](xs: List[A]): A = {
val m = implicitly[Monoid[A]]
xs.foldLeft(m.mzero)(m.mappend)
}
If I already have in my scope a Monoid[Int] that has mappend = _ + _, can I call my function with an explicit Monoid[Int] which has a different behavior? Or the only solution is to use a more verbose syntax with a second argument implicit monoid: Monoid[Int]?
The code exemple comes from this Scalaz tutorial: http://eed3si9n.com/learning-scalaz/sum+function.html
At the end the author shows an exemple of providing explicitly the Monoid, but he didn't use context bounds:
scala> val multiMonoid: Monoid[Int] = new Monoid[Int] {
def mappend(a: Int, b: Int): Int = a * b
def mzero: Int = 1
}
multiMonoid: Monoid[Int] = $anon$1#48655fb6
scala> sum(List(1, 2, 3, 4))(multiMonoid)
res14: Int = 24
Context bounds are nothing more than syntactic sugar.
The following:
def sum[A: Monoid](xs: List[A])
is extactly the same as:
def sum[A](xs: List[A])(implicit evidence: Monoid[A])
This means that regardless of the way you defined your sum method (either with a context bound or with an implicit parameter), you can explicitly pass the implicit parameter as in sum(List(1, 2, 3, 4))(multiMonoid)