-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathLazy.scala
72 lines (54 loc) · 2.38 KB
/
Lazy.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package learnshapeless
import shapeless._
import test.illTyped
object Ch09_LazyDemo extends App {
val l: MyList[Int] = Cons(1, Nil)
import Show._
/** This exercise demos the Lazy[T] typeclass, which relaxes the conservative termination checker for implicit resolution,
* which can often mistakenly reject valid recursive implicits. */
/** Exercises: Answer each of the following
* 1. What happens if show(l) is removed from the illTyped wrapper?
* What does the error mean?
* What specifically about this situation causes it to happen
* */
illTyped("""show(l)""")
/** 2. Does the error happen when required implicits are manually/explicitly provided?
* Make a prediction, then uncomment below and find out.
* can you explain why/why not? */
//show(l)(showMyList(showCons(showInt, showMyList)))
/** 3. Fix it using typeclass Lazy[T]. Replace showCons with `showCons2` and study the differences.
* Apply the same changes anywhere else you think are needed, so that `show(l)` compiles and works
* Note: your changes will probably make exercise 2 above not compile; just comment it out. */
}
sealed trait MyList[+T]
case class Cons[T](hd: T, tl: MyList[T]) extends MyList[T]
sealed trait Nil extends MyList[Nothing]
case object Nil extends Nil
trait Show[T] {
def apply(t: T): String
}
object Show {
def show[T](t: T)(implicit s: Show[T]) = s(t)
// Base case for Int
implicit def showInt: Show[Int] = new Show[Int] {
def apply(t: Int) = t.toString
}
// Base case for Nil
implicit def showNil: Show[Nil] = new Show[Nil] {
def apply(t: Nil) = "Nil"
}
// Case for Cons[T]: note (mutually) recursive implicit argument referencing Show[MyList[T]]
implicit def showCons[T](implicit st: Show[T], sl: Show[MyList[T]]): Show[Cons[T]] = new Show[Cons[T]] {
def apply(t: Cons[T]) = s"Cons(${show(t.hd)(st)}, ${show(t.tl)(sl)})"
}
// implicit def showCons2[T](implicit st: Show[T], sl: Lazy[Show[MyList[T]]]): Show[Cons[T]] = new Show[Cons[T]] {
// def apply(t: Cons[T]) = s"Cons(${show(t.hd)(st)}, ${show(t.tl)(sl.value)})"
// }
// Case for MyList[T]: note (mutually) recursive implicit argument referencing Show[Cons[T]]
implicit def showMyList[T](implicit sc: Show[Cons[T]]): Show[MyList[T]] = new Show[MyList[T]] {
def apply(t: MyList[T]) = t match {
case n: Nil => show(n)
case c: Cons[T] => show(c)(sc)
}
}
}