【问题标题】:Functional Programming exercise with Scala使用 Scala 进行函数式编程练习
【发布时间】:2016-08-21 10:52:32
【问题描述】:

我最近开始阅读 Paul Chiusano 和 Rúnar Bjarnason 撰写的Scala 中的函数式编程一书,作为学习 FP 的一种方式。我想学习它,因为它会打开我的脑袋,改变我的思维方式,并希望让我成为一个整体上更好的程序员,或者我希望如此。

在他们的书中,Chp。 3,他们定义了一个基本的单链表类型如下:

package fpinscala.datastructures

sealed trait List[+A]
case object Nil extends List[Nothing]
case class Cons[+A](head: A, tail: List[A]) extends List[A]

object List {
    def sum(ints: List[Int]): Int = ints match {
    case Nil => 0
    case Cons(x,xs) => x + sum(xs)
    }
    def product(ds: List[Double]): Double = ds match {
    case Nil => 1.0
    case Cons(0.0, _) => 0.0
    case Cons(x,xs) => x * product(xs)
    }
    def apply[A](as: A*): List[A] =
    if (as.isEmpty) Nil
    else Cons(as.head, apply(as.tail: _*))
}

我现在正致力于实现 tail 方法,它的工作方式类似于 Scala 库中定义的 tail 方法。我猜这里的想法是在 List 对象中定义一个 tail 方法,他们称之为 companion 方法,然后在另一个文件(如 Main 文件)中正常调用它。

到目前为止,我有这个:

def tail[A](ls: List[A]): List[A] = ls match {
    case Nil => Nil
    case Cons(x,xs) => xs
    }

然后我在另一个文件夹中创建了一个主文件:

package fpinscala.datastructures

object Main {
    def main(args:Array[String]):Unit = {
       println("Hello, Scala !! ")
       val example = Cons(1, Cons(2, Cons(3, Nil)))
    val example2 = List(1,2,3)
       val example3 = Nil
    val total = List.tail(example)
    val total2 = List.tail(example3)
    println(total2)
}
}

这有效并给了我:

Hello, Scala !! 
Cons(2,Cons(3,Nil))

我的问题是:

这是否是编写 tail 方法的正确方法,可能如作者所愿?这个包结构是否正确?因为我觉得很不对劲,虽然我只是跟着作者的包走。

我也不知道我是否应该使用特定类型而不是编写多态方法(这是名字吗?)...

请耐心等待,因为我是 FP 艺术的新手。

【问题讨论】:

  • 这对我来说似乎非常好。虽然:1.您不想在密封特征之外显示 Cons,所以最好将其设为私有 2.为什么在主函数中需要示例和总变量?
  • 谢谢!我如何“封装”缺点以使其私有?我理解这个例子,但是改变实际的类对我来说还是有点太多了,而且在书中他们要求添加简单的方法,比如 tail 等等......所以我很茫然。关于例子,好吧,我想测试一下?

标签: scala functional-programming


【解决方案1】:

在默认的 Scala 列表实现中,尝试获取空列表的尾部会引发 UnsupportedOperationException。所以你可能想要更像

def tail[A](ls: List[A]): List[A] = ls match {
    case Nil => throw new UnsupportedOperationException()
    case Cons(x,xs) => xs
}

此外,qantik 的回答是,他建议使用 :: 运算符将与 Scala 的默认列表实现一起使用,但由于在此自定义列表实现中没有定义 :: 方法,因此它不起作用。

最后,您可能需要考虑定义 tail ,而不是这样做

val list = List(1, 2, 3)
val restOfList = tail(list). 

你可以这样做

val list = List(1, 2, 3)
val restOfList = list.tail

这需要在 List trait 上定义方法,而不是在 List 对象中。

【讨论】:

    【解决方案2】:

    看起来不错。怎么样?

    def tail[A](xs: List[A]): List[A] = xs match {
        case Nil => Nil
        case head :: xxs => xxs
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-22
      • 2011-11-01
      • 2011-08-24
      • 2014-08-07
      • 2014-03-06
      相关资源
      最近更新 更多