0

I am trying to build my custom generic list class with fold, rightfold, leftfold and map functions. But i don't want to build using Cons constructor and i don't want to use std scala lib or inherent scala list object. Is it possible to create list object using fold right function.

As per SF Scala: Gabriel Claramunt, All about a Fold scala list using fold vs Cons https://www.youtube.com/watch?v=rdEFiMNxr0I at 22.03 in above video , he explained that fold replaces data type constructors.

enter image description here

Recursive aapproach:-

      import scala.annotation.tailrec


    sealed abstract class myList[+A] {


      def head():A 

      def tail():myList[A] 

      def apply[A](as: A*): myList[A] ={

        if (as.isEmpty) Nil

        else Cons(as.head, apply(as.tail: _*))
      }



      def isEmpty():Boolean ={
        this match {
          case Nil => true
          case  _: myList[A] => false
        }
      }

      def preappend[B>:A](x: B): myList[B] ={
        if (isEmpty)  make(x)
        else  Cons(x, this)
      }

      //@tailrec
      final def append[B>:A](x: B): myList[B] ={

        def appendrecc(lst:myList[B], a:B):myList[B]={
          lst match  {
            case Nil =>Cons(a, Nil)
            case x:myList[A]=> appendrecc(x,a) 
          }
        }
        Console.println(this.toString , x.toString)
        if (this.isEmpty) make(x)
        else  Cons(this.head, this.tail.append(x))
      }

      def print()={
          this.map(println)
       }

      def make[B>:A](x:B): myList[B] ={

          this match {
            case Cons(xh:B, xs:Cons[B]) => Cons(xh, xs.make(x)) 
            case Cons(xh : B, Nil)=>Cons(xh,Cons(x, Nil))
            case _=>Cons(x, Nil)
          }
      }


      def map[A,B](f: (A) => B): myList[B] = { 

          this match {
            case Cons(xh : A, Nil) => Cons(f(xh),Nil) 
            case Cons(xh:A, xs:Cons[A]) => Cons(f(xh),xs.map(f ))
            case a:myList[A] =>Cons(f(a.head),a.tail.map(f ))
          }
      }
      /**
       * Combines all elements of this list into value.
       *
       * Time - O(n)
       * Space - O(n)
       */
      def fold[B](n: B)(op: (B, A) => B): B = {
        def loop(l: myList[A], a: B): B =
          if (l.isEmpty) a
          else loop(l.tail, op(a, l.head))

        loop(this, n)
      }

      def foldLeft[B](z: B)(f: (B, A) => B): B = {
          var acc = z
          var these = this
          while (!these.isEmpty) {
            acc = f(acc, these.head)
            these = these.tail
          }
          acc
        }

      def foldRight[D,C](z: D)(f: (C, D) => D): D = 
      try { 
        // ...
        this match {
        case Cons(x:C,xs:Cons[C])=>{println("1case->"+this.toString);f(x, xs.foldRight(z)(f))}
        case Cons(x:C, Nil) =>{println("2case->"+this.toString+"x->"+x.toString+"z-> "+z.toString);f(x,Nil.foldRight(z)(f))}
        case y:C=>f(y,z)
        }
      } catch {
        case e: Exception =>{ println(this.toString);e.printStackTrace(); sys.exit;}
      }



      def length[B>:A]():Int={ 
        this match {
          case _: myList[B] => foldRight(0) {(y:A,x:Int ) =>x+1
            }
          }

      }


      def appendprint[B>:A]():String={ 
        this match {
          case z: myList[B] => foldRight("") {(y:A, x:String ) =>
                      //Console.println(this)
                      y.toString+" --->"+x
            }         
          }

      }


      def fail(m: String) = throw new NoSuchElementException(m)

    }


    case object Nil extends myList[Nothing]{
    override  def head: Nothing = fail("An empty list.")
    override  def tail: myList[Nothing] = fail("An empty list.")

    override  def isEmpty: Boolean = true
    }

    case class Cons[+A](headc: A,  tailc: myList[A]) extends myList[A] {


    override def isEmpty: Boolean = false
    override def head():A ={
        headc
      }
    override def tail():myList[A] ={
        tailc
      }

    }

    case class truck(
          numberPlate:String

      )


  object myList {

    /**
     * An empty list.
     */
    def empty[A]: myList[A] = Nil

    /**
     * A smart constructor for list's cons.
     */
    def make[A](x: A, t: myList[A] = Nil): myList[A] = Cons(x, t)

    /**
     * Creates a new list from given 'xs' sequence.
     *
     * Time - O(n)
     * Space - O(1)
     */
    def apply[A](xs: A*): myList[A] = {
      var r: myList[A] = myList.empty
      for (x <- xs.reverse) r = r.append(x)
      r
    }

  }

    object Main {
      def main(args: Array[String]) {
          var a= new  truck("1233bsd")
          var b = new  truck("dsads334")
          var lst = List(a,b)
          var e = myList(a,b)
          Console.println(e)
          Console.println("printing length of list ")
          Console.println(e.length())
          Console.println("copy list using fold operations------>")
          var f=e.foldRight(Nil: myList[truck])((next, acc:myList[truck]) =>{println("fold function->"+next.toString); Cons[truck](next, acc)})
          Console.println(f)
      }
    }

could you help building generic list list class using purely functional approach.

Errors , i am getting:-

(Nil,truck(dsads334))
(Cons(truck(dsads334),Nil),truck(1233bsd))
(Nil,truck(1233bsd))
Cons(truck(dsads334),Cons(truck(1233bsd),Nil))
printing length of list 
1case->Cons(truck(dsads334),Cons(truck(1233bsd),Nil))
2case->Cons(truck(1233bsd),Nil)x->truck(1233bsd)z-> 0
3
copy list using fold operations------>
1case->Cons(truck(dsads334),Cons(truck(1233bsd),Nil))
2case->Cons(truck(1233bsd),Nil)x->truck(1233bsd)z-> Nil
Nil
java.lang.ClassCastException: Nil$ cannot be cast to scala.runtime.Nothing$
    at Main$$anonfun$1.apply(mylist-v3.scala:193)
    at myList.foldRight(mylist-v3.scala:98)
    at myList.foldRight(mylist-v3.scala:97)
    at myList.foldRight(mylist-v3.scala:96)
    at Main$.main(mylist-v3.scala:193)
    at Main.main(mylist-v3.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at scala.reflect.internal.util.ScalaClassLoader$$anonfun$run$1.apply(ScalaClassLoader.scala:70)
    at scala.reflect.internal.util.ScalaClassLoader$class.asContext(ScalaClassLoader.scala:31)
    at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.asContext(ScalaClassLoader.scala:101)
    at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:70)
    at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
    at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
    at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
    at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
    at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
    at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:65)
    at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
    at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

My approach may not be correct. i am looking solution too.

5
  • 2
    What are the errors? Commented Jan 29, 2018 at 15:23
  • i have update question with compilation errors. Commented Jan 29, 2018 at 15:29
  • Could you formulate the question in such a way that it becomes comprehensible for those who do not want to watch the entire lecture? Do you want to implement a list structure without using any classes at all, and relying on functions and closures instead, that is, implement the idea that "There is no difference between a list and the foldr. The foldr is the list."? Commented Jan 29, 2018 at 18:28
  • i have edited question to make it more comprehensible. As per talk Fold can replace data type constructors so you can build list using fold. i am not able to understood how . Commented Jan 30, 2018 at 6:34
  • You say, "But i don't want to build using Cons constructor." That's where I'm a little confused. Folds aren't for constructing lists. Folds are for consuming lists. The fold functions let you take a list object and consume it completely to any other type, but they don't let you construct lists. Commented Feb 4, 2018 at 20:00

1 Answer 1

1

You can bootstrap a MyList[A] using the foldRight method of scala.collection.List:

List(Trunk("123"), Trunk("456"))
  .foldRight(Nil: MyList[Trunk])((next, acc) => Cons(next, acc))

I wouldn't really consider this cheating, since Scala has special built-ins (variadic function application syntax) to construct lists from syntactically-built arrays, anyway.

Sign up to request clarification or add additional context in comments.

3 Comments

Just thought of this today: ``` def positives(n: Int, acc: MyList[Int] = Nil): MyList[Int] = if (n < 1) acc else positives(n - 1, Cons(n, acc)) ```
I tried your approach and updated code(in original question) with my custom fold right operations and building list as you shown above but always getting runtime error "java.lang.ClassCastException: Nil$ cannot be cast to scala.runtime.Nothing$" . from Fold Right operations . I have updated code in original questions
I don't think you understood my suggestion, and I think that I, in turn, did not understand your question. I thought you were asking how to avoid the tedium or writing things out by hand using Cons(3, Cons(2, Cons(1, Nil))), but now I think that you're asking something else, and I don't really understand your question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.