纯粹使用功能方法构建scala自定义列表

时间:2018-01-29 15:21:45

标签: scala generics functional-programming

我正在尝试使用fold,rightfold,leftfold和map函数构建我的自定义通用列表类。但我不想使用Cons构造函数构建,我不想使用std scala lib或固有的scala列表对象。是否可以使用右侧折叠功能创建列表对象。

根据SF Scala:Gabriel Claramunt,所有关于折叠 scala list using fold vs Cons https://www.youtube.com/watch?v=rdEFiMNxr0I 在上面的视频中,他在22.03解释说,fold替换了数据类型构造函数。

enter image description here

递归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)
      }
    }

您可以使用纯粹的功能方法帮助构建通用列表列表类。

错误,我得到: -

(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)

我的方法可能不正确。我也在寻找解决方案。

1 个答案:

答案 0 :(得分:1)

您可以使用MyList[A]的{​​{1}}方法引导foldRight

scala.collection.List

我不会真的考虑这种作弊,因为Scala有特殊的内置函数(可变函数应用程序语法)来构造来自语法构建数组的列表。