Re: Implicit conversion to Functor

No replies
Sebastien Bocq
Joined: 2008-12-18,
Yup, that was the trick, thanks!

I declared Tree as an abstract class instead of a case class and then the compiler was able to flag my invalid match statement. Yet the compiler warns me that that my match statement is incomplete with a very strange message:

match is not exhaustive! missing combination \$anon\$1 missing combination \$anon missing combination \$anon missing combination \$anon missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon missing combination \$anon\$1 missing combination \$anon missing combination \$anon missing combination \$anon\$1 missing combination
\$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon missing combination \$anon missing combination \$anon\$1 missing combination \$anon\$1 missing combination \$anon missing combination \$anon\$1

Is there a way to clear this warning while keeping Tree as a sealed class?

Here is the new code.

trait Functor[A, T[A]] {
def fmap[B](f:A => B):T[B]
}

sealed abstract class Tree[A] {

override def toString = {
this match {
case Leaf(x) => x.toString
case Branch(a,b) => "[" + a + "," + b + "]"
case _ => "Fck"
}
}

}
case class Leaf[A](a:A) extends Tree[A]
case class Branch[A](a:Tree[A], b:Tree[A]) extends Tree[A]

object Tree {

implicit def treeAsFunctor[A](t:Tree[A]):Tree[A] with Functor[A, Tree] = {
new Tree[A] with Functor[A, Tree] {
def fmap[B](f:A => B):Tree[B] = {
t match { // Warning match is not exhaustive...
case Leaf(x) => Leaf(f(x))
case Branch(a,b) => Branch(a fmap f, b fmap f)
}
}
}
}

}

object FunctorTest {
def main(args : Array[String]) : Unit = {
val t = Branch(Leaf(0), Branch(Leaf(1), Leaf(2)))
println(t)
// [0,[1,2]]
println(t fmap(_+1))
}
}

Thanks,
Sebastien

2008/12/24 Erkki Lindpere <erkki [at] lap [dot] ee>
In the implicit conversion you are creating a new class which is neither Leaf nor Branch, and so

*this* match {...}

can't match those patterns. I think you wanted

*t* match {...}

(to match the original node that is given as argument to the implicit conversion)

Sebastien Bocq wrote:
Hello,

I'm trying to convert an arbitrary type to a Functor using implicit conversions (see code below). it sounded like an interesting idea at the time but it absolutely doesn't work.

trait Functor[A, T[A]] {
def fmap[B](f:A => B):T[B]
}

sealed case class Tree[A]() {
override def toString = {
this match {
case Leaf(x) => x.toString
case Branch(a,b) => "[" + a + "," + b + "]"
case _ => "Fck" // Compiler complains that match is non exhaustive because
// "Tree[A] with Functor[A, Tree]" (see implicit conversion below)
// generates anonymous class Tree\$\$anon that extends Tree[A]
}      }
}

case class Leaf[A](a:A) extends Tree[A]
case class Branch[A](a:Tree[A], b:Tree[A]) extends Tree[A]

object Tree {
implicit def treeAsFunctor[A](t:Tree[A]):Tree[A] with Functor[A, Tree] = {
new Tree[A] with Functor[A, Tree] {
def fmap[B](f:A => B):Tree[B] = {
this match { // Line 27
case Leaf(x) => Leaf(f(x))
case Branch(a,b) => Branch(a fmap f, b fmap f)
// Here the compiler does not complain that a case is missing, but it causes
// the match error (compiler bug?)
}
}      }
}
}

object FunctorTest {
def main(args : Array[String]) : Unit = {
val t = Branch(Leaf(0), Branch(Leaf(1), Leaf(2)))
println(t)
// [0,[1,2]]
println(t fmap(_+1))
// Exception in thread "main" scala.MatchError: Fck
// at com.Tree\$\$anon\$1.fmap(Functor.scala:27)
// at com.Tree\$\$anon\$1.fmap(Functor.scala:25)
// at com.FunctorTest\$.main(Functor.scala:41)
// at com.FunctorTest.main(Functor.scala)
}
}

Can someone explain me the match error and/or provide some suggestions to fix this code?

Thanks,
Sebastien