Scala计划 - 难以理解

时间:2014-08-07 20:48:39

标签: scala functional-programming

有人可以解释下面的代码吗?我发现它很难理解。如果有更好的解决方案,也请告诉我。

更新:我知道基本知识,如currying,模式匹配,List,map功能。但我不了解在flatMapSublists函数中使用两个泛型A和B的需要,' sublist @'。我认为,由于缺乏知识的点点滴滴,我无法理解整体解决方案。

  
    

查找nCr的所有值

  
//     Example:
//     scala> combinations(3, List('a, 'b, 'c, 'd, 'e, 'f))
//     res0: List[List[Symbol]] = List(List('a, 'b, 'c), List('a, 'b, 'd), List('a, 'b, 'e), ...

解决方案:

// flatMapSublists is like list.flatMap, but instead of passing each element
// to the function, it passes successive sublists of L.


def flatMapSublists[A, B](ls: List[A])(f: (List[A]) => List[B]): List[B] =
  ls match {
    case Nil => Nil
    case sublist @ (_ :: tail) => f(sublist) ::: flatMapSublists(tail)(f)
  }

  def ncr[A](n: Int, ls: List[A]): List[List[A]] =

    if (n == 0) List(Nil)
    else flatMapSublists(ls) { sl =>
      ncr(n - 1, sl.tail) map { sl.head :: _ }
  }

ncr(3, List('a, 'b, 'c, 'd, 'e, 'f))

输出:

List(List('a, 'b, 'c), List('a, 'b, 'd), List('a, 'b, 'e), List('a, 'b, 'f), List('a, 'c, 'd), List('a, 'c, 'e), List('a,'c, 'f), List('a, 'd, 'e), List('a, 'd, 'f), List('a, 'e, 'f), List('b, 'c,'d), List('b, 'c, 'e), List('b, 'c, 'f), List('b, 'd, 'e), List('b, 'd, 'f), List('b, 'e, 'f), List('c, 'd, 'e), List('c, 'd, 'f), List('c, 'e, 'f), List('d, 'e, 'f))

来源:http://aperiodic.net/phil/scala/s-99/p26.scala

非常感谢!

2 个答案:

答案 0 :(得分:1)

关于通用类型用法:

acjay解释了在flatmap中使用泛型的一般原则。 为了给出一些关于如何确定多种类型与一种类型的需求的指示,让我们看一下这两种函数的输入和输出类型。

NCR: 输入:列表[A] 输出:列出[列表[A]]

flatmapLists: 输入: 列表[A] f:列表[A] =>列表[B]

输出: 列表[B]

如果我们将函数flatMapSublists的使用限制为函数f:它只支持List [A] =>列表[List [A]],我们可以将接口更改为仅使用一个泛型类型,它仍然可以工作。

def flatMapSublists[A](ls: List[A])(f: (List[A]) => List[List[A]]): List[List[A]] = 

关于"子列表@"

当ls不是Nil时,子列表与ls相同,所以你不需要指定它,你可以直接使用ls。所以更新的函数如下所示:


 def flatMapSublists[A](ls: List[A])(f: (List[A]) => List[List[A]]): List[List[A]] = {
   ls match {
     case Nil => Nil
     case (_ :: tail) => {
          f(ls) ::: flatMapSublists(tail)(f)
     }
   }
 }

替代实施

遵循传统的递归方法(尽管不是尾递归)


  def p26_ncr_recursive[A](n: Int, ls: List[A]): List[List[A]] = {
    if (n==0) List(Nil)
    else ls match {
      case Nil => Nil
      case head :: tail =>
        p26_ncr_recursive(n - 1, tail).map {
          head :: _
        } ::: p26_ncr_recursive(n, tail)
    }
  }

答案 1 :(得分:0)

  

但我不了解在flatMapSublists函数中使用两个泛型A和B的需要,...

所有flatMapmap都有两个泛型,一个用于列表的类型,一个用于列出的类型。您可能不习惯在一个地方看到两者,因为标准库集合将这些集合定义为在预先存在的List上具有一个类型参数的方法,该参数定义class级别的其他类型参数。

  

'子列表@'

此语法仅将变量定义为整个匹配模式。当@的右侧不仅仅是一个简单的类型匹配,而是一个模式,并且你想要整个值时,可以使用它。您可能会认为@是对左侧新val的分配。

如果您有其他问题,请发表评论。逻辑是有点棘手的,所以我建议尝试为一个非常简单的案例ncr(3, List('a, 'b, 'c, 'd))推理事物的流动。如果有帮助,您可以使用println s来丢弃代码。