Reputation: 2982
How do I remove explicit casting asInstanceOf[XList[B]] in Cons(f(a), b).asInstanceOf[XList[B]]
inside map
function? Or perhaps redesign reduce
and map
functions altogether? Thanks
trait XList[+A]
case object Empty extends XList[Nothing]
case class Cons[A](x: A, xs: XList[A]) extends XList[A]
object XList {
def apply[A](as: A*):XList[A] = if (as.isEmpty) Empty else Cons(as.head, apply(as.tail: _*))
def empty[A]: XList[A] = Empty
}
def reduce[A, B](f: B => A => B)(b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f)(f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] = reduce((b: XList[B]) => (a: A) => Cons(f(a), b).asInstanceOf[XList[B]])(XList.empty[B])(xs)
Upvotes: 1
Views: 69
Reputation: 149626
You can either widen Cons
to a XList[B]
at the call site by providing the type parameters explicitly:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce[A, XList[B]]((b: XList[B]) => (a: A) => Cons(f(a), b))(XList.empty[B])(xs)
Or use type ascription:
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b): XList[B])(XList.empty[B])(xs)
As a side note, reduce
is traditionally more strict at the method definition than what you've written. reduce usually looks like this:
def reduce[A](a0: A, a: A): A
Implicitly requiring a non empty collection to begin with. What you've implemented is similar in structure to a foldLeft
, which has this structure (from Scalas collection library):
def foldLeft[B](z: B)(op: (B, A) => B): B
Upvotes: 0
Reputation: 44977
You can merge two argument lists into one by replacing )(
by ,
:
def reduce[A, B](f: B => A => B, b: B)(xs: XList[A]): B = xs match {
case Empty => b
case Cons(y, ys) => reduce(f, f(b)(y))(ys)
}
def map[A, B](f: A => B)(xs: XList[A]): XList[B] =
reduce((b: XList[B]) => (a: A) => Cons(f(a), b), XList.empty[B])(xs)
This will force the type inference algorithm to consider both first arguments of reduce
before making up its mind about what B
is supposed to be.
Upvotes: 1