Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala—匿名函数的递归_Scala_Recursion_Anonymous Function - Fatal编程技术网

Scala—匿名函数的递归

Scala—匿名函数的递归,scala,recursion,anonymous-function,Scala,Recursion,Anonymous Function,我正在研究scala实验室的东西,我正在构建一个函数,最终将返回如下内容: tails(List(1,2,3,4))=List(List(1,2,3,4),List(2,3,4),List(3,4),List(4),List()) 我通过使用两个函数并在第二个函数上使用一些递归实现了这一点 def tails[T](l: List[T]): List[List[T]] = { if ( l.length > 1 )trailUtil(List() ::: List(l)) els

我正在研究scala实验室的东西,我正在构建一个函数,最终将返回如下内容:
tails(List(1,2,3,4))=List(List(1,2,3,4),List(2,3,4),List(3,4),List(4),List())

我通过使用两个函数并在第二个函数上使用一些递归实现了这一点

def tails[T](l: List[T]): List[List[T]] = {
    if ( l.length > 1 )trailUtil(List() ::: List(l))
    else List() ::: List(l);
}

def trailUtil[T](l:List[List[T]]) : List[List[T]] = {
    if ( l.last.length == 0)l
    else trailUtil(l :+ l.last.init);
}
这一切都很好,但是我需要两个函数来完成这项工作,这让我感到很烦恼。我尝试为匿名函数切换:
trailtil(List()::List(l))
,但出现了以下错误
类型不匹配;从IDE中找到:List[List[T]]required:Int

val ret : List[List[T]] = (ll:List[List[T]]) => {
    if ( ll.last.length == 0) ll else ret(ll :+ ll.last.init)
}
ret(List() ::: List(1))
请有人告诉我我做错了什么,或者用一种更好的方法来做这件事

(我确实看了这篇文章,但不同的类型对我来说并不合适):

这个怎么样:

def tails[T](l: List[T]): List[List[T]] = 
  l match {
    case h :: tail => l :: tails(tail)
    case Nil => List(Nil)
  }
还有一个不那么惯用的版本:

def tails[T](input: List[T]): List[List[T]] =
    if(input.isEmpty)
        List(List())
    else
        input :: tails(input.tail)
顺便说一句,尽量避免使用
List.length
,它在O(n)时间内运行

更新:根据tenshi的建议,尾部递归解决方案:

@tailrec def tails[T](l: List[T], init: List[List[T]] = Nil): List[List[T]] =
    l match {
        case h :: tail => tails(tail, l :: init)
        case Nil => init
    }

实际上,您可以在另一个
def
中定义
def
。它允许定义实际具有名称的函数,该名称可被引用并用于递归。下面是如何实现
tails

def tails[T](l: List[T]) = {
    @annotation.tailrec
    def ret(ll: List[List[T]]): List[List[T]] =
        if (ll.last.isEmpty) ll 
        else ret(ll :+ ll.last.tail)

    ret(l :: Nil)
}
这个实现也是尾部递归的。我添加了
@annotation.tailrec
注释,以确保它确实是(如果不是,代码将不会编译)


您还可以使用内置函数
tails
(请参阅):


tails
返回
Iterator
,所以如果需要,您需要将其转换为list(就像我所做的那样)。此外,结果最后还将包含一个额外的空值(在我的示例中,结果将是
列表(列表(1,2,3,4),列表(2,3,4),列表(3,4),列表(4),列表())
),因此您需要处理它。

您所做的错误是:

val ret : List[List[T]]
因此,
ret
是一个T列表。然后您可以执行以下操作:

ret(ll :+ ll.last.init)
这意味着您正在对T的列表调用方法
apply
。列表的
apply
方法采用
Int
参数,并返回具有该索引的元素。例如:

scala> List("first", "second", "third")(2)
res0: java.lang.String = third
我假设您想要编写
val ret:List[List[T]=>List[List[T]]
,也就是说,一个函数接受
List[List[T]
并返回一个
List[List[T]
。然后您会遇到其他问题,因为
val
在其定义中是指自身。要解决这个问题,您可以用一个
惰性val
替换它:

def tails[T](l: List[T]): List[List[T]] = {
  lazy val ret : List[List[T]] => List[List[T]] = { (ll:List[List[T]]) => 
    if ( ll.last.length == 0) ll 
    else ret(ll :+ ll.last.init)
  }
  if ( l.length > 1 )ret(List() ::: List(l))
  else List() ::: List(l);
}

但是,当然,简单的解决方法是按照建议将一个
def
放在另一个
中。

您也可以使用折叠:

val l = List(1,2,3,4)

l.foldLeft(List[List[Int]](l))(  (outerList,element) => {
    println(outerList)
    outerList.head.tail :: outerList
})

第一个参数列表是起始值/累加器。第二个函数是修饰符。通常,它修改起始值,然后将其传递给列表中的每个元素。我加入了一个println,这样你可以在列表迭代时看到累加器。

这很好,但我只了解其中的一半。我不理解的主要问题是
x
从何而来。谢谢你的长度信息@洛里扎克:嗯,我也不明白
x
是从哪里来的,我的解决方案中没有
x
;-)。试着用纸和笔浏览一下这段代码,你会看到递归在这里是如何工作的。WTF!我想我看到了一些东西!在
情况h
中,
h
来自何处?h是一个变量,其值来自被匹配的对象。它只是指尾巴。如果您愿意,可以在case语句中使用它。例如,您可以说:case first::second::third::Nil=>println(first+“”+second+“”+third)。这将匹配任何具有三个元素的列表,并将这些元素分配给变量first、second和third。用法:scala>List(1,2,3)match{case first::second::third::Nil=>println(first+“”+second+“”+third)case}>println(“No match”)}1,2,3列表(1,2,3,4)打印“No match”,这是模式匹配的一部分。这是一个非常广泛的话题,请参见。从Prolog到Haskell再到Clojure,您可以在多种语言中找到相同的结构。虽然这是真的,但它与我的结构没有太大的不同。@locrizak:我不认为您可以使用一级函数进行递归,为此您需要
def
。Ballin!你知道使用foldLeft比其他例子有没有额外的开销吗?我不这么认为。看一看源代码:106 override/*TraversableLike*/107 def foldLeft[B](z:B)(f:(B,a)=>B):B={108 var acc=z 109 var this=this 110而(!this.isEmpty){111 acc=f(acc,this.head)112 this=this.tail 113}114 acc 115}哇,没有干净地发布。无论如何,fold left/:我总是忘记它,只是键入foldLeftA。许多scala集合库的编写看起来像是递归的,但实际上由于jvm和堆栈大小的限制,它们是以迭代方式编写的。这就是一个例子。这里有一个很好的解释他们试图实现的目标:(也摘自我极力推荐的《Scala编程》一书)。我想自己尝试一些锻炼,所以我找到了scala实验室。现在每当有一个我不懂的练习时,我都会蹦蹦跳跳,你的问题的标题包括“匿名”。这些不是匿名函数,其形式为
(inputs)=>表达式
,即没有名称。我不知道在Scala中,是否可以递归一个没有名字的函数。在Javascript中,可以使用不推荐的。
val l = List(1,2,3,4)

l.foldLeft(List[List[Int]](l))(  (outerList,element) => {
    println(outerList)
    outerList.head.tail :: outerList
})