def createFloatBuffer(data: Option[Quaternion]*): Option[FloatBuffer] = data match {
...
}
def createFloatBuffer(data: Option[Vector3f]*): Option[FloatBuffer] = data match {
...
}
This code will not compile due to the two methods having the same method signature. None type would not know which method to call.
I could just rename the methods, however I would like to this overloading style in my code.
After type erasure this two methods become createFloatBuffer(data: Option), and all types information is lost and not available at run time.
As a workaround I can suggest you to use TypeClass pattern.
case class Quaternion(v: Int)
case class Vector3f(v: Int)
case class FloatBuffer(v: Int)
sealed trait FloatBufferBuilder[T] {
def createFloatBuffer(data: Option[T]): Option[FloatBuffer]
}
implicit object QuaternionFloatBufferBuilder extends FloatBufferBuilder[Quaternion] {
def createFloatBuffer(data: Option[Quaternion]) = data.map(d => FloatBuffer(d.v))
}
implicit object Vector3fFloatBufferBuilder extends FloatBufferBuilder[Vector3f] {
def createFloatBuffer(data: Option[Vector3f]) = data.map(d => FloatBuffer(d.v))
}
def createFloatBuffer[T : FloatBufferBuilder](data: Option[T]): Option[FloatBuffer] =
implicitly[FloatBufferBuilder[T]].createFloatBuffer(data)
println(createFloatBuffer(Some(Quaternion(1))))
println(createFloatBuffer(Some(Vector3f(1))))
Magnet Pattern could also interesting for you: http://spray.io/blog/2012-12-13-the-magnet-pattern/
This is the use case for:
scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
<console>:10: error: double definition:
def f(is: Int*): Int at line 10 and
def f(ds: Double*): Int at line 10
have same type after erasure: (is: Seq)Int
object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
^
scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*)(implicit dummy: DummyImplicit) = 43 }
defined object X
scala> X f 1
res2: Int = 42
scala> X f 1.0
res3: Int = 43
Related
I'd like to overload a method based on generics - so something like this:
case class Indexed2dArr[Dim0Type, Dim1Type] (
indices: (List[Dim0Type], List[Dim1Type]),
array: List[List[Float]],
) {
def getSliceAtIndexLocation(i: Dim0Type): (List[Dim1Type], List[Float]) = ???
def getSliceAtIndexLocation(i: Dim1Type): (List[Dim0Type], List[Float]) = ???
}
So if getSliceAtIndexLocation is called with a parameter of Dim0Type, it returns a single-dimensioned slice of the orginal array, with an index of Dim1Type. And vice-versa for calling with Dim1Type.
This raises a double definition compiler error - that the two methods have the same type after type erasure, this type being (i: Object): Tuple2. Is there a valid way to wrangle this or is it straight-up impossible?
Try either DummyImplicit
case class Indexed2dArr[Dim0Type, Dim1Type] (
indices: (List[Dim0Type], List[Dim1Type]),
array: List[List[Float]],
) {
def getSliceAtIndexLocation(i: Dim0Type): (List[Dim1Type], List[Float]) = ???
def getSliceAtIndexLocation(i: Dim1Type)(implicit
di: DummyImplicit): (List[Dim0Type], List[Float]) = ???
}
or type class pattern
case class Indexed2dArr[Dim0Type, Dim1Type] (
indices: (List[Dim0Type], List[Dim1Type]),
array: List[List[Float]],
) {
def getSliceAtIndexLocation[A](i: A)(implicit tc: TC[A]): tc.Out = tc(i)
trait TC[A] {
type B
type Out = TC.MkOut[B]
def apply(i: A): Out
}
object TC {
type MkOut[B] = (List[B], List[Float])
type Aux[A, B0] = TC[A] { type B = B0 }
def instance[A, B0](f: A => MkOut[B0]): Aux[A, B0] = new TC[A] {
override type B = B0
override def apply(i: A): Out = f(i)
}
implicit val dim0Type: Aux[Dim0Type, Dim1Type] = instance(i => ???)
implicit val dim1Type: Aux[Dim1Type, Dim0Type] = instance(i => ???)
}
}
or magnet pattern
import scala.language.implicitConversions
case class Indexed2dArr[Dim0Type, Dim1Type] (
indices: (List[Dim0Type], List[Dim1Type]),
array: List[List[Float]],
) {
def getSliceAtIndexLocation(m: Magnet): m.Out = m()
trait Magnet {
type B
type Out = Magnet.MkOut[B]
def apply(): Out
}
object Magnet {
type MkOut[B] = (List[B], List[Float])
type Aux[B0] = Magnet { type B = B0 }
def instance[B0](x: MkOut[B0]): Aux[B0] = new Magnet {
override type B = B0
override def apply(): Out = x
}
implicit def dim0Type(i: Dim0Type): Aux[Dim1Type] = instance(???)
implicit def dim1Type(i: Dim1Type): Aux[Dim0Type] = instance(???)
}
}
I am trying to create a generic class that only accepts java.math.BigDecimal or Long. Here is the code:
class myClass[T]()
{
def display( x : T) = {
println(x.doubleValue())
}
}
val input = new java.math.BigDecimal(100)
// val input = 100L
val x = new myClass[java.math.BigDecimal]()
x.display(input)
Clearly I will have this error: ScalaFiddle.scala:22: error: value doubleValue is not a member of type parameter T.
I tried playing with implicit conversion, view bound, and context bound for hours. No result so far. Is there any way I can force Scala to believe me that T has method .doubleValue()? (java.big.Decimal and Long both has .doubleValue() method, but they don't share same super-class)
Try structural type bound
class myClass[T <: {def doubleValue(): Double}]
or type class
trait HasDoubleValue[T] {
def doubleValue(t: T): Double
}
object HasDoubleValue {
implicit val long: HasDoubleValue[Long] = t => t.doubleValue
implicit val bigDecimal: HasDoubleValue[BigDecimal] = t => t.doubleValue
}
implicit class DoubleValueOps[T: HasDoubleValue](x: T) {
def doubleValue(): Double = implicitly[HasDoubleValue[T]].doubleValue(x)
}
class myClass[T: HasDoubleValue]
In Dotty (Scala 3) we might use union types, for example,
class myClass[T <: (Long | java.math.BigDecimal)]() {
def display(x: T) =
println(
x match {
case t: Long => t.doubleValue
case t: java.math.BigDecimal => t.doubleValue
}
)
}
new myClass().display(new java.math.BigDecimal(100)) // OK
new myClass().display(100L) // OK
new myClass().display("100") // Error
scala> class C private (n: Number) {
| def this(i: Long) = this(i: Number)
| def this(b: BigDecimal) = this(b: Number)
| def d = n.doubleValue
| }
defined class C
scala> new C(42L).d
res0: Double = 42.0
scala> new C(BigDecimal("123456789")).d
res1: Double = 1.23456789E8
or with a type parameter
scala> class C[A <: Number] private (n: A) { def d = n.doubleValue ; def a = n } ; object C {
| def apply(i: Long) = new C(i: Number) ; def apply(b: BigDecimal) = new C(b) }
defined class C
defined object C
I'm working through chapter 9 of Functional Programming in Scala (the Manning book by Paul Chiusano and RĂșnar Bjarnason). There are inline examples from the chapter such as the following which is presented after exercise 9.1:
char('a').many.slice.map(_.size) ** char('b').many1.slice.map(_.size)
Having implemented the methods up to that point I'm unable to run this example in the scala repl. The code can be found here.
I did the following to start the repl:
./sbt
> ~exercises/console
scala> import fpinscala.parsing._
Running simply char('a') gives me the following error:
scala> char('a')
<console>:18: error: not found: value char
char('a')
^
I'm new to scala so it's possible that I've missed something. Should I be able to run the methods from a trait like this at the repl? If so, what am I missing? In the other chapters I tried to tinker with the code as soon as possible in order to get a feel for concepts and to experiment with the APIs. However I'm unable to run the most simple of inline examples at this point.
The type parameter Parser[+_] is left abstract for almost the entire chapter. Only in the exercise 9.12 you are supposed to try to come up with your own implementation, and a possible solution is provided only in 9.6.2.
Until then, you have several possibilities if you want to experiment with implementation of methods that produce Parser[A] for some type A:
Add them directly to the Parsers trait. There, you can use all other methods, like e.g. char.
Parameterize your code over all possible type constructors Parser[+_], as it is shown on page 158 in 9.4. The section starts with the disclaimer that "We don't have an implementation of our algebra yet", but this is not required, because the implementation is assumed to be an argument that will be supplied later:
def jsonParser[Err, Parser[+_]](P: Parsers[Err, Parser]): Parser[JSON] = {
import P._ // now `char` is available.
???
}
This here works with your code:
def myParser[P[+_]](P: Parsers[P]) = {
import P._
char('a').many.slice.map(_.size) **
char('b').many1.slice.map(_.size)
}
Alternatively, just extend Parsers by yet another trait, still leaving the Parser[+_] abstract:
trait MyParser[Parser[+_]] extends Parsers[Parser] {
def ab =
char('a').many.slice.map(_.size) **
char('b').many1.slice.map(_.size)
}
Here is your own code, with two examples that definitely compile:
import language.higherKinds
import language.implicitConversions
trait Parsers[Parser[+_]] { self => // so inner classes may call methods of trait
def run[A](p: Parser[A])(input: String): Either[ParseError,A]
implicit def string(s: String): Parser[String]
implicit def operators[A](p: Parser[A]) = ParserOps[A](p)
implicit def asStringParser[A](a: A)(implicit f: A => Parser[String]):
ParserOps[String] = ParserOps(f(a))
def char(c: Char): Parser[Char] =
string(c.toString) map (_.charAt(0))
def or[A](s1: Parser[A], s2: Parser[A]): Parser[A]
def listOfN[A](n: Int, p: Parser[A]): Parser[List[A]]
def many[A](p: Parser[A]): Parser[List[A]]
def slice[A](p: Parser[A]): Parser[String]
def many1[A](p: Parser[A]): Parser[List[A]] =
map2(p, many(p))(_ :: _)
def product[A,B](p: Parser[A], p2: Parser[B]): Parser[(A,B)]
def map[A,B](a: Parser[A])(f: A => B): Parser[B]
def map2[A,B,C](p: Parser[A], p2: Parser[B])(f: (A,B) => C): Parser[C] =
map(product(p, p2))(f.tupled)
def succeed[A](a: A): Parser[A] =
string("") map (_ => a)
case class ParserOps[A](p: Parser[A]) {
def |[B>:A](p2: Parser[B]): Parser[B] = self.or(p,p2)
def or[B>:A](p2: => Parser[B]): Parser[B] = self.or(p,p2)
def many = self.many(p)
def map[B](f: A => B): Parser[B] = self.map(p)(f)
def slice: Parser[String] = self.slice(p)
def many1: Parser[List[A]] = self.many1(p)
def **[B](p2: => Parser[B]): Parser[(A,B)] =
self.product(p,p2)
def product[A,B](p: Parser[A], p2: Parser[B]): Parser[(A,B)] = self.product(p, p2)
def map2[A,B,C](p: Parser[A], p2: Parser[B])(f: (A,B) => C): Parser[C] = self.map2(p, p2)(f)
}
}
case class Location(input: String, offset: Int = 0) {
lazy val line = input.slice(0,offset+1).count(_ == '\n') + 1
lazy val col = input.slice(0,offset+1).reverse.indexOf('\n')
def toError(msg: String): ParseError =
ParseError(List((this, msg)))
def advanceBy(n: Int) = copy(offset = offset+n)
/* Returns the line corresponding to this location */
def currentLine: String =
if (input.length > 1) input.lines.drop(line-1).next
else ""
}
case class ParseError(stack: List[(Location,String)] = List(),
otherFailures: List[ParseError] = List()) {
}
object Parsers {
}
def myParser[P[+_]](P: Parsers[P]) = {
import P._
char('a').many.slice.map(_.size) **
char('b').many1.slice.map(_.size)
}
trait MyParser[P[+_]] extends Parsers[P] {
def ab =
char('a').many.slice.map(_.size) **
char('b').many1.slice.map(_.size)
}
Note that ParserOps have been modified: you had redundant parameters A and p in few methods.
I need to implement function to. I have the following working code:
object Main {
val m = 0
val km = 1
implicit def wrapM(v: Int) = new {
def m = v
}
implicit def wrapKm(v: Int) = new {
def km = v * 1000
}
implicit class toWrap(fromVal: Int) {
def too (value: Int): Double = {
if (value.equals(km)) {
fromVal / 1000.0
} else {
0
}
}
}
def main(args:Array[String])
{
println(53.m too km)
}
}
But there is one problem. I use too name, instead of to. If I rename it to to, then I get the error:
Error:(30, 16) type mismatch;
found : Int
required: ?{def to(x$1: ? >: Int): ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method intWrapper in class LowPriorityImplicits of type (x: Int)scala.runtime.RichInt
and method toWrap in object Main of type (fromVal: Int)Main.toWrap
are possible conversion functions from Int to ?{def to(x$1: ? >: Int): ?}
println(53.m to km)
^
It is due to the fact, that there is one other function to - scala.runtime.RichInt#to.
Scala does not allow define two implicits with same arguments set in one context....
But there is a way. You should work with different type in toWrap implicit , instead of standard scala Int.
Check sample below.
My idea is to implement method to for some wrapper class IntWrap instead of standard Int
case class IntWrap(v: Int) {
}
val m = 0
val km = 1
implicit def wrapM(v: Int) = new {
def m = IntWrap(v)
}
implicit def wrapKm(v: Int) = new {
def km = v * 1000
}
implicit class toWrap(fromVal: IntWrap) {
def to(value: Int): Double = {
if (value.equals(km)) {
fromVal.v / 1000.0
} else {
0
}
}
}
def main(args:Array[String])
{
println(53.m to km)
}
I am trying to write some extension methods for the Scala collections, and running into trouble fully generifying them.
A first attempt at tailOption yields something like:
implicit class TailOption[A, Repr <: GenTraversableLike[A, Repr]](val repr: Repr) {
def tailOption: Option[Repr] =
if (repr.isEmpty) None
else Some(repr.tail)
}
unfortunately, this doesn't work:
scala> List(1,2,3).tailOption
<console>:19: error: value tailOption is not a member of List[Int]
List(1,2,3).tailOption
Scala 2.10 provides the IsTraversableLike type-class to help adapt this sort of thing for all collections (including odd ones, like Strings).
With this I can for instance implement tailOption quite easily:
implicit class TailOption[Repr](val r: Repr)(implicit fr: IsTraversableLike[Repr]) {
def tailOption: Option[Repr] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.tail)
}
}
scala> List(1,2,3).tailOption
res12: Option[List[Int]] = Some(List(2, 3))
scala> "one".tailOption
res13: Option[String] = Some(ne)
The result is of the correct type: Option[<input-type>]. Specifically, I have been able to preserve the Repr type when calling methods that return Repr, like `tail.
Unfortunately, I can't seem to use this trick to preserve the type of the elements of the collection. I can't call methods that return an element.
IsTraversableLike does have a member A but it doesn't seem very useful. In particular I can't reconstruct my original element type and the member is not equivalent in type. For instance, without further work, headTailOption looks like this:
implicit class HeadTailOption[Repr](val r: Repr)(implicit val fr: IsTraversableLike[Repr]) {
def headTailOption: Option[(fr.A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
scala> val Some((c, _)) = "one".headTailOption
c: _1.fr.A forSome { val _1: HeadTailOption[String] } = o
As we can see, c has a wonderfully baroque type. But, this type is not equivalent to Char:
scala> val fr = implicitly[IsTraversableLike[String]]
fr: scala.collection.generic.IsTraversableLike[String] = scala.collection.generic.IsTraversableLike$$anon$1#60ab6a84
scala> implicitly[fr.A <:< Char]
<console>:25: error: Cannot prove that fr.A <:< Char.
implicitly[fr.A <:< Char]
I have tried all sorts of tricks including having Repr[A] <: GenTraversableLike[A, Repr[A]] none of which help. Can anyone work out the magic sauce to make headTailOption return the right types for:
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
A partial answer. You have probably started from the scaladoc example for IsTraversableLike. It still uses the "old approach" of separating implicit conversion and instantiating the wrapper class, instead of going in one step through an implicit class. It turns out that the "old approach" does work:
import collection.GenTraversableLike
import collection.generic.IsTraversableLike
final class HeadTailOptionImpl[A, Repr](repr: GenTraversableLike[A, Repr]) {
def headTailOption: Option[(A, Repr)] = {
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
implicit def headTailOption[Repr](r: Repr)(implicit fr: IsTraversableLike[Repr]):
HeadTailOptionImpl[fr.A,Repr] = new HeadTailOptionImpl(fr.conversion(r))
// `c` looks still weird: `scala.collection.generic.IsTraversableLike.stringRepr.A`
val Some((c, _)) = "one".headTailOption
val d: Char = c // ...but it really is a `Char`!
val headTailString: Option[(Char, String)] = "one".headTailOption
val headTailList: Option[(Int, List[Int])] = List(1,2,3).headTailOption
As Miles points out, the split seems essential for this to work with the implicit search and type inference.
Another solution, although of course less elegant, is to give up the unification of strings and collections:
trait HeadTailOptionLike[A, Repr] {
def headTailOption: Option[(A, Repr)]
}
implicit class GenHeadTailOption[A, Repr](repr: GenTraversableLike[A, Repr])
extends HeadTailOptionLike[A, Repr] {
def headTailOption =
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
implicit class StringHeadTailOption(repr: String)
extends HeadTailOptionLike[Char, String] {
def headTailOption =
if (repr.isEmpty) None
else Some(repr.head -> repr.tail) // could use repr.charAt(0) -> repr.substring(1)
}
List(1,2,3).headTailOption
"one".headTailOption
You can write it as an implicit class if you extract the type A from the IsTraversableLike.
import collection.generic.IsTraversableLike
implicit class HeadTailOption[Repr,A0](val r: Repr)(implicit val fr: IsTraversableLike[Repr]{ type A = A0 }) {
def headTailOption: Option[(A0, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
Or equivalently:
import collection.generic.IsTraversableLike
type IsTraversableLikeAux[Repr,A0] = IsTraversableLike[Repr]{ type A = A0 }
implicit class HeadTailOption[Repr,A](val r: Repr)(implicit val fr: IsTraversableLikeAux[Repr,A]) {
def headTailOption: Option[(A, Repr)] = {
val repr = fr.conversion(r)
if (repr.isEmpty) None
else Some(repr.head -> repr.tail)
}
}
And then everything works fine.
scala> val Some((c, _)) = "one".headTailOption
c: scala.collection.generic.IsTraversableLike.stringRepr.A = o
scala> c.isSpaceChar
res0: Boolean = false
The compiler knows that scala.collection.generic.IsTraversableLike.stringRepr.A is the same as Char.