Shapeless' Lazy and implicit parameter - scala

I am trying to trace the sequence of construction (lots of println) and have this code
https://scastie.scala-lang.org/4DRXuhUZS8mN551eI7vN3Q
import shapeless._
object abc {
sealed trait List[+T]
case class Cons[T](hd: T, tl: List[T]) extends List[T]
sealed trait Nil extends List[Nothing]
case object Nil extends Nil
trait Show[T] {
def apply(t: T): String
}
object Show {
// Base case for Int
implicit def showInt: Show[Int] = new Show[Int] {
println("222")
def apply(t: Int) = t.toString
println("222 end")
}
// Base case for Nil
implicit def showNil: Show[Nil] = new Show[Nil] {
def apply(t: Nil) = "Nil"
}
// without Lazy, resoving sc requires resolving sl, which in turn sc -- infinite looping
// Lazy stops this looping and saying I got this, so go on to resolve showCons using proxy st and sl. real st and sl can be accessed using st.value and sl.value
// which will lazily resolved.
// Case for Cons[T]: note (mutually) recursive implicit argument referencing Show[List[T]]
implicit def showCons[T](implicit st: Lazy[Show[T]], sl: Lazy[Show[List[T]]]): Show[Cons[T]] = {
val t = new Show[Cons[T]] {
println(" 111")
def apply(t: Cons[T]) = {
println(" apply 111 ")
println(s" try to show ${t.tl}")
val sss = s"Cons(${show(t.hd)(st.value)}, ${show(t.tl)(sl.value)})"
println(" apply 111 end ")
sss
}
println(" 111 end") // the reason 111 comes before 333 at the beginning is determined by internal algorithm of Lazy
}
t
}
// Case for List[T]: note (mutually) recursive implicit argument referencing Show[Cons[T]]
implicit def showList[T](implicit sc: Lazy[Show[Cons[T]]]): Show[List[T]] = new Show[List[T]] {
println(" 333")
def apply(t: List[T]) = t match {
case n: Nil => show(n)
case c: Cons[T] => {
println(" apply 333")
val tmp = show(c)(sc.value) //explicitly passing down parameter
println(" apply 333 end")
tmp
}
}
println(" 333 end")
}
}
def show[T](t: T)(implicit s: Show[T]) = s(t)
def main(args: Array[String]): Unit = {
val l: List[Int] = Cons(1, Cons(2, Cons(3, Nil)))
println(show(l))
}
}
and when I run it, it prints out
111
111 end
333
333 end
apply 333
apply 111
try to show Cons(2,Cons(3,Nil))
222
222 end
333
333 end
apply 333
apply 111
try to show Cons(3,Nil)
apply 333
apply 111
try to show Nil
apply 111 end
apply 333 end
apply 111 end
apply 333 end
apply 111 end
apply 333 end
Cons(1, Cons(2, Cons(3, Nil)))
why 111 and 111 end got executed (constructed) before 333 and 333 end even though implicit sc: Lazy[Show[Cons[T]]] has Lazy in it? Shouldn't it be delayed till sc.value got referenced?
I can see that st and sl are lazily constructed, but wondering why sc is immediately constructed? Does Lazy algorithm thinks that it is ok to construct sc without causing an infinite loop issue?

Related

In Scala 3, how to define unapply method to extract type argument in pattern matching?

So I found some esoteric code when upgrading an old Scala 2 library, the gist of it looks like this:
object MatchExtractTypeArg {
import scala.reflect.runtime.universe.TypeTag
def mapType(k: TypeTag[_], v: TypeTag[_]) = {
(k, v) match {
case (k: TypeTag[a], v: TypeTag[b]) =>
implicit val kkk = k
implicit val vvv = v
implicitly[TypeTag[Map[a, b]]]
}
}
def main(args: Array[String]): Unit = {
val t1 = implicitly[TypeTag[Int]]
val t2 = implicitly[TypeTag[String]]
val r = mapType(t1, t2)
println(r)
}
}
the pattern matching case (k: TypeTag[List[a]], v: TypeTag[List[b]]) is fairly difficult to understand. after some investigation, I could only speculate that the following unapply function was used on k & v to determine type a & b:
// (in scala.reflect.runtime.universe.TypeTag definition)
def unapply[T](ttag: TypeTag[T]): Option[Type] = Some(ttag.tpe)
After Scala 3 upgrade, the above code should becomes:
object MatchExtractTypeArg {
def mapType(k: Typeable[_], v: Typeable[_]) = {
(k, v) match {
case (k: Typeable[a], v: Typeable[b]) =>
given kk: Typeable[a] = k
given vv: Typeable[b] = v
summon[Typeable[Map[a, b]]]
}
}
def main(args: Array[String]): Unit = {
val t1 = summon[Typeable[Int]]
val t2 = summon[Typeable[String]]
val r = mapType(t1, t2)
println(r)
}
}
It apparently compiles without a problem, but when trying to figure out its mechanism, I found that the unapply method being defined under Typeable has an entirely different signature, and can't extract any type argument.
Am I not upgrading code properly? How could it be possible that the new extractor still works in Scala 3?

how to print a collection as valid code in scala

Assume I have
val x = List("a","b","c")
I'd like to have a function f which when called, returns
List("a","b","c")
Currently, println(x) just prints List(a,b,c) which will not compile when compiled/pasted into an Scala-Notebook or Unit-Test.
I'm stuck to find a general solution which also works for Seq[Double] etc , I managed to get something for Seq[String] by re-adding the quotes, but I'm unable to get a proper solution for all collection types
Sounds like you want custom type class Show
trait Show[T] {
def show(t: T): String
}
trait LowPriorityShow {
implicit def default[T]: Show[T] = _.toString
}
object Show extends LowPriorityShow {
implicit val str: Show[String] = s => s""""$s""""
// other exceptions for element types
implicit def list[T: Show]: Show[List[T]] = _.map(show(_)).mkString("List(", ",", ")")
implicit def seq[T: Show]: Show[Seq[T]] = _.map(show(_)).mkString("Seq(", ",", ")")
// other exceptions for collection types
}
def show[T](t: T)(implicit s: Show[T]): String = s.show(t)
val x = List("a","b","c")
show(x) //List("a","b","c")
val x1 = Seq("a","b","c")
show(x1) //Seq("a","b","c")
You can try to replace instances for collections (Show.list, Show.seq...) with more generic
import shapeless.Typeable
implicit def collection[Col[X] <: Iterable[X], T: Show](implicit ev: Typeable[Col[_]]): Show[Col[T]] = {
val col = Typeable[Col[_]].describe.takeWhile(_ != '[')
_.map(show(_)).mkString(s"$col(", ",", ")")
}
You'll have to check yourself whether the result is always a valid code in Scala.

Scala - not a case class nor does it have method .unapply

I am quite new to Scala and got a few unresolved problems with the following code:
object exprs{
println("Welcome to the Scala worksheet")
def show(e: Expr): String = e match {
case Number(x) => x.toString
case Sum(l, r) => show(l) + " + " + show(r)
}
show(Sum(Number(1), Number(44)))
}
trait Expr {
def isNumber: Boolean
def isSum: Boolean
def numValue: Int
def leftOp: Expr
def rightOp: Expr
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
}
class Number(n: Int) extends Expr {
override def isNumber: Boolean = true
override def isSum: Boolean = false
override def numValue: Int = n
override def leftOp: Expr = throw new Error("Number.leftOp")
override def rightOp: Expr = throw new Error("Number.rightOp")
}
class Sum(e1: Expr, e2: Expr) extends Expr {
override def isNumber: Boolean = false
override def isSum: Boolean = true
override def numValue: Int = e1.eval + e2.eval
override def leftOp: Expr = e1
override def rightOp: Expr = e2
}
I get the following errors:
Error: object Number is not a case class, nor does it have an unapply/unapplySeq member
Error: not found: value Sum
How to resolve them? Thanks in advance
In Scala case class are like class with extra goodies + some other properties.
For a normal class,
class A(i: Int, s: String)
You can not create its instance like this,
val a = A(5, "five") // this will not work
You will have to use new to create new instance.
val a = new A(5, "five")
Now lets say we have case class,
case class B(i: Int, s: String)
We can create a new instance of B like this,
val b = B(5, "five")
The reason this works with case class is because case class have an auto-created companion objects with them, which provides several utilities including an apply and unapply method.
So, this usage val b = B(5, "five") is actually val b = B.apply(5, "five"). And here B is not the class B but the companion object B which is actually provieds apply method.
Similarly Scala pattern matching uses the unapply (unapplySeq for SeqLike patterns) methods provided by companion object. And hence normal class instances do not work with pattern matching.
Lets say you wanted to defined a class and not a case class for some specific reason but still want to use them with pattern-matching etc, you can provide its companion object with the required methods by yourselves.
class C(val i: Int, val s: String) {
}
object C {
def apply(i: Int, s: String) = new C(i, s)
def unapply(c: C) = Some((c.i, c.s))
}
// now you can use any of the following to create instances,
val c1 = new C(5, "five")
val c2 = C.apply(5, "five")
val c3 = C(5, "five")
// you can also use pattern matching,
c1 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
c2 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
Also, as you are new to learning Scala you should read http://danielwestheide.com/scala/neophytes.html which is probably the best resource for any Scala beginner.

scalaz, read and map the lines of a file

The following code to read and map the lines of a file works ok:
def readLines(fileName: String) = scala.io.Source.fromFile(fileName).getLines
def toInt(line: String) = line.toInt
val numbers: Iterator[Int] = readLines("/tmp/file.txt").map(toInt).map(_ * 2)
println(numbers.toList)
I get an iterator of Ints if the executing goes well. But the program throws an exception if the file is not found, or some line contains letters.
How can I transform the program to use scalaz monads and get a Disjunction[Exception, List[Int]]?
I tried this on scalaz 7.2.6, but it does not compile:
import scalaz.Scalaz._
import scalaz._
def readLines(fileName: String): Disjunction[Any, List[String]] =
try { scala.io.Source.fromFile(fileName).getLines.toList.right }
catch { case e: java.io.IOException => e.left}
def toInt(line: String): Disjunction[Any, Int] =
try { line.toInt.right }
catch { case e: NumberFormatException => e.left}
val numbers: Disjunction[Any, Int] = for {
lines: List[String] <- readLines("/tmp/file.txt")
line: String <- lines
n: Int <- toInt(line)
} yield (n * 2)
it fails to compile with these errors:
Error:(89, 37) could not find implicit value for parameter M: scalaz.Monoid[Any]
lines: List[String] <- readLines("/tmp/file.txt")
Error:(89, 37) not enough arguments for method filter: (implicit M: scalaz.Monoid[Any])scalaz.\/[Any,List[String]].
Unspecified value parameter M.
lines: List[String] <- readLines("/tmp/file.txt")
Error:(91, 20) could not find implicit value for parameter M: scalaz.Monoid[Any]
n: Int <- toInt(line)
Error:(91, 20) not enough arguments for method filter: (implicit M: scalaz.Monoid[Any])scalaz.\/[Any,Int].
Unspecified value parameter M.
n: Int <- toInt(line)
I don't understand the errors. what is the problem?
and how to improve this code, so that it does not read all the file into memory, but it reads and maps each line at a time?
Update: Answer from Filippo
import scalaz._
def readLines(fileName: String) = \/.fromTryCatchThrowable[List[String], Exception] {
scala.io.Source.fromFile(fileName).getLines.toList
}
def toInt(line: String) = \/.fromTryCatchThrowable[Int, NumberFormatException](line.toInt)
type λ[+A] = Exception \/ A
val numbers = for {
line: String <- ListT[λ, String](readLines("/tmp/file.txt"))
n: Int <- ListT[λ, Int](toInt(line).map(List(_)))
} yield n * 2
println(numbers)
To answer the second part of your question, I would simply use the Iterator out of the fromFile method:
val lines: Iterator[String] = scala.io.Source.fromFile(fileName).getLines
If you want to use toInt to convert String to Int:
import scala.util.Try
def toInt(line: String): Iterator[Int] =
Try(line.toInt).map(Iterator(_)).getOrElse(Iterator.empty)
Then numbers could look like:
val numbers = readLines("/tmp/file.txt").flatMap(toInt).map(_ * 2)
EDIT
Due the presence of all these try and catch, if you want to keep using that monadic-for I would suggest to check a scalaz helper like .fromTryCatchThrowable on Disjunction:
import scalaz._, Scalaz._
def readLines(fileName: String): Disjunction[Exception, List[String]] =
Disjunction.fromTryCatchThrowable(scala.io.Source.fromFile(fileName).getLines.toList)
def toInt(line: String): Disjunction[Exception, Int] =
Disjunction.fromTryCatchThrowable(line.toInt)
Now we also have Exception instead of Any as the left type.
val numbers = for {
lines: List[String] <- readLines("/tmp/file.txt")
line: String <- lines // The problem is here
n: Int <- toInt(line)
} yield n * 2
The problem with this monadic-for is that the first and third line are using the Disjunction context but the second one uses the List monad. Using a monad transformer like ListT or DisjunctionT here is possible but probably overkill.
EDIT - to reply the comment
As mentioned, if we want a single monadic-for comprehension, we need a monad transformer, in this case ListT. The Disjunction has two type parameters while a Monad M[_] obviously only one. We need to handle this "extra type parameter", for instance using type lambda:
def readLines(fileName: String) = \/.fromTryCatchThrowable[List[String], Exception] {
fromFile(fileName).getLines.toList
}
val listTLines = ListT[({type λ[+a] = Exception \/ a})#λ, String](readLines("/tmp/file.txt"))
What is the type of listTLines? The ListT transformer: ListT[\/[Exception, +?], String]
The last step in the original for-comprehension was toInt:
def toInt(line: String) = \/.fromTryCatchThrowable[Int, NumberFormatException](line.toInt)
val listTNumber = ListT[\/[Exception, +?], Int](toInt("line"))
What is the type of listTNumber? It doesn't even compile, because the toInt return an Int and not a List[Int]. We need a ListT to join that for-comprehension, one trick could be changing listTNumber to:
val listTNumber = ListT[\/[Exception, +?], Int](toInt("line").map(List(_)))
Now we have both steps:
val numbers = for {
line: String <- ListT[\/[Exception, +?], String](readLines("/tmp/file.txt"))
n: Int <- ListT[\/[Exception, +?], Int](toInt(line).map(List(_)))
} yield n * 2
scala> numbers.run.getOrElse(List.empty) foreach println
2
20
200
If you are wondering why all this unwrapping:
scala> val unwrap1 = numbers.run
unwrap1: scalaz.\/[Exception,List[Int]] = \/-(List(2, 20, 200))
scala> val unwrap2 = unwrap1.getOrElse(List())
unwrap2: List[Int] = List(2, 20, 200)
scala> unwrap2 foreach println
2
20
200
(assuming that the sample file contains the lines: 1, 10, 100)
EDIT - comment about compilation issues
The code above compiles thanks to the Kind Projector plugin:
addCompilerPlugin("org.spire-math" % "kind-projector_2.11" % "0.5.2")
With Kind Projector we can have anonymous types like:
Either[Int, +?] // equivalent to: type R[+A] = Either[Int, A]
Instead of:
type IntOrA[A] = Either[Int, A]
// or
({type L[A] = Either[Int, A]})#L
First, the compiler alerts that you´re using for comprehensions mixing types. Your code is transformed by the compiler as that :
readLines("/tmp/file.txt") flatMap { lines => lines } map { line => toInt(line) }
The definition of flatMap is:
def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B]
In your case F is the \/, and this flatMap { lines => lines } is wrong. The compiler alerts with a message like this "List[Nothing] required: scalaz.\/[Any,Int]" because treats list as one function with no parameters and List[Nothing] as result type. Change your code like that:
import scalaz.Scalaz._
import scalaz._
def readLines(fileName: String): Disjunction[Any, List[String]] =
try { scala.io.Source.fromFile(fileName).getLines.toList.right }
catch { case e: java.io.IOException => e.left}
def toInt(line: List[String]): Disjunction[Any, List[Int]] =
try { (line map { _ toInt }).right }
catch { case e: NumberFormatException => e.left}
val numbers = for {
lines <- readLines("/tmp/file.txt")
n <- toInt(lines)
} yield (n map (_ * 2))
That works.
For read line by line maybe FileInputStream can be easier:
fis = new FileInputStream("/tmp/file.txt");
reader = new BufferedReader(new InputStreamReader(fis));
String line = reader.readLine();
while(line != null){
System.out.println(line);
line = reader.readLine();
}
Or you can test the readline function from Source class.

Option method signature, function already defined in this scope

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