views:

559

answers:

4

How to define this class in scala

data NestedList a = Elem a | List [NestedList a]

This in Haskell means a NestedList is a Type which can contain either Elem or another NestedList. Is it possible to do these kind of recursive definitions in scala?

Actually this is what I am trying to acheive

Check Problem 7 here in this page.

Updated....
Follwing the answers below, I created the NestedList Trait and case classes for Elem and NList. Trying to implement the flatten, I am stuck here..

def flatten[T](xs: NestedList[T]): List[T] = xs match{
   case Elem(xs) => List(xs)
   //case NList //have to fill this case
}
+2  A: 

Algebraic Data Types from Haskell are idiomatically translated into sealed class hierarchies in Scala.

For example:

sealed abstract class List[+A]

case class Nil extends List[Nothing]

case class Elem[T](head: T, tail: List[T]) extends List[T]

UPDATE

Thomas's answer shows the recursive type definition nicely. However, it is interesting that you can't make NList a case class -- a type error is reported for the synthesised method sameElements, which is used in equals. This sounds similar to: https://lampsvn.epfl.ch/trac/scala/ticket/2867

It works is the repeated parameters are replaced with Seq:

sealed trait NestedList[A]
case class Elem[A](e : A) extends NestedList[A]
case class NList[A](val e : Seq[NestedList[A]]) extends NestedList[A]
retronym
Aren't these algebraic data types?
Thomas Jung
amended, thanks!
retronym
I am not sure, I followed it, Can you please show me an example of how to define the same class which I defined in the question.
Teja Kantamneni
@retronym Thanks for the update. But I am still not able to get the solution for the problem(see the problem link in question). In a nutshell, I am trying to achieve something equivalent to this haskell function... data NestedList a = Elem a | List [NestedList a] flatten :: NestedList a -> [a] flatten (Elem x) = [x] flatten (List x) = concatMap flatten x
Teja Kantamneni
@retronym please check the update. Here is the code snippet..http://snipt.org/vmkl
Teja Kantamneni
I don't see any error here.
Daniel
@Daniel: I'm using 2.8 beta1. #2867 was fixed 5 weeks ago... not sure if that's in the beta or not.
retronym
+3  A: 

This should work.

sealed trait NestedList[A]
case class Elem[A](val e : A) extends NestedList[A]
case class NList[A](val e : Seq[NestedList[A]]) extends NestedList[A]

def flatten[T](xs: NestedList[T]): Seq[T] = xs match{
   case Elem(x) => List(x)
   case NList(xs) => xs flatMap (flatten(_)) 
}
Thomas Jung
Please use case classes.
Dario
+1  A: 
sealed abstract class NestedList[A] {
  def flatten: NList[A]
}

case class Elem[A](e: A) extends NestedList[A] {
  override def flatten = NList(Elem(e))
}

case class NList[A](es: NestedList[A]*) extends NestedList[A] {
  override def flatten = NList(es flatMap (_.flatten.es): _*)
}
Daniel
This produces an error message with 2.8 Beta 1: <console>:5: error: type arguments [NestedList[A]] do not conform to method same Elements's type parameter bounds [B >: NestedList[Any]] case class NList[A](es: NestedList[A]*) extends NestedList[A]
Thomas Jung
@Thomas it works on my newer Scala 2.8.
Daniel
@Thomas by the way, if you are running it on REPL, remember to place all of it inside an object, so that they are considered to be defined in the same module.
Daniel
+3  A: 

See 99 problems in Scala for Scala versions of the problems.

The linked solution from that site is:

def flatten(ls: List[Any]): List[Any] = ls flatMap {
  case ms: List[_] => flatten(ms)
  case e => List(e)
}
Ben Lings
A + 1 for the link,
Teja Kantamneni