Created
November 2, 2020 06:58
-
-
Save DDR0/022f1b468ad028ae3fda561b479cbf15 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import scala.annotation.tailrec | |
// generic version | |
sealed trait List[A] { | |
@tailrec | |
final def length(counter: Int=0): Int = | |
this match { | |
case Pair(_, tail:List[A]) => tail.length(counter+1) | |
case End() => counter | |
case x => | |
//If it's not a pair or and end, print it for debugging. | |
print("Could not match ") | |
print(x.getClass) | |
print(". Is List? ") | |
println(x.isInstanceOf[List[A]]) | |
-1 | |
} | |
} | |
case class End[A]() extends List[A] | |
case class Pair[A](head: A, tail: List[A]) extends List[A] | |
Pair('A', Pair('B', Pair('C', End()))) | |
Pair('A', Pair('B', Pair('C', End()))).length() | |
End().length() | |
println("done") | |
// non-generic version | |
sealed trait IntList extends List[Int] { | |
@tailrec | |
final def sum(counter: Int=0): Int = | |
this match { | |
case IntPair(head, tail) => tail.sum(head + counter) | |
case IntEnd() => counter | |
} | |
} | |
final case class IntEnd() extends IntList | |
final case class IntPair(head: Int, tail: IntList) extends IntList | |
val example = IntPair(1, IntPair(2, IntPair(3, IntEnd()))) | |
assert(example.sum() == 6) | |
assert(example.tail.sum() == 5) | |
assert(IntEnd().sum() == 0) | |
//This fails because I can't get IntList to be a subclass of List, | |
//and the List function can't "see" IntList. | |
//The problem is that we want the IntEnd to inherit from IntList for | |
//the sum function, but also End so the length function can match. | |
//The inheritance pattern should look like this: | |
// | |
// List | |
// ↙ ↓ ↘ | |
// Pair IntList End | |
// ↓ ↙ ↘ ↓ | |
// IntPair IntEnd | |
// | |
//I can't figure out how to get IntEnd to inherit from End and | |
//IntList at the same time. Trying to inherit from case classes is | |
//Not A Thing™ - if we try something like | |
// | |
// > final case class IntEnd() extends End with IntList | |
// | |
//we get | |
// | |
// > case class IntEnd has case ancestor $line649.$read.$iw.$iw.End, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes. | |
// | |
//Furthermore, if we try to make an intermediate trait we can inherit | |
//from, like | |
// | |
// > sealed trait EndT[A] extends List[A] | |
// | |
//and use is like | |
// | |
// > case class End[A]() extends EndT[A] | |
// | |
//and something like | |
// | |
// > case class IntEnd() extends EndT[Int] with IntList | |
// | |
//then we can't match against EndT in our List's length | |
//implementation because it's not in scope. The same goes for | |
// | |
// > abstract case class EndT[A]() extends List[A] | |
// > case class End[A]() extends EndT[A] | |
// | |
//- we can match against EndT, but we can't inherit it for End. | |
//Now, if do the obvious and make End a normal class, inheriting | |
//from the abstract case class EndT, we *can* match against EndT | |
//and do our switch statement that way and it works with the addition | |
//of a couple of `new` statements. However, we cannot use this | |
//strategy with the Int variants' .sum function, because we need our | |
//objects to be both a PairT and an IntPairT for that, which they — | |
//being both class objects — can't be. We can't get rid of the class | |
//objects either, because then we can't match against them like we | |
//want to. | |
// | |
//At this point, I'm out of ideas. | |
example.length() | |
IntEnd().length() | |
println("done int") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment