Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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_Haskell_Functional Programming_Iteration - Fatal编程技术网

Scala 如何简洁地表达函数迭代?

Scala 如何简洁地表达函数迭代?,scala,haskell,functional-programming,iteration,Scala,Haskell,Functional Programming,Iteration,有没有一种简洁、地道的表达方式?也就是说,给定一个数n和一个函数f::a->a,我想表示\x->f(…(f(x))…),其中f被应用n-次 当然,我可以为此制作自己的递归函数,但如果有一种方法可以使用现有的工具或库很快表达出来,我会很感兴趣。 到目前为止,我有以下想法: \n f x->foldr(const f)x[1..n] \n->appEndo。麦康卡特。复制n。Endo 但是它们都使用中间列表,并且不是很简洁 到目前为止,我发现的最短的一个使用半群: \n f->appEndo。

有没有一种简洁、地道的表达方式?也就是说,给定一个数
n
和一个函数
f::a->a
,我想表示
\x->f(…(f(x))…)
,其中
f
被应用
n
-次

当然,我可以为此制作自己的递归函数,但如果有一种方法可以使用现有的工具或库很快表达出来,我会很感兴趣。

到目前为止,我有以下想法:

  • \n f x->foldr(const f)x[1..n]
  • \n->appEndo。麦康卡特。复制n。Endo
但是它们都使用中间列表,并且不是很简洁

到目前为止,我发现的最短的一个使用半群:

  • \n f->appEndo。时间1p(n-1)。Endo
但它只适用于正数(不适用于0)

我主要关注Haskell中的解决方案,但我也对Scala解决方案或其他函数式语言感兴趣。

在Scala中:

Function chain Seq.fill(n)(f)

看。惰性版本:
函数链Stream.fill(n)(f)

因为Haskell深受数学的影响,所以从您链接到的Wikipedia页面几乎可以直接转换为该语言

看看这个:

现在在哈斯克尔:

iterateF 0 _ = id
iterateF n f = f . iterateF (n - 1) f
def iterate[T](f: T=>T, n: Int): T=>T = (x: T) => n match {
  case 0 => x
  case _ => iterate(f, n-1)(f(x))
}
很整洁,是吗

这是什么?这是一种典型的递归模式。哈斯凯勒通常是如何看待这一点的?我们用褶皱来处理它!因此,在重构之后,我们将进行以下转换:

iterateF :: Int -> (a -> a) -> (a -> a)
iterateF n f = foldr (.) id (replicate n f)
或无积分,如果您愿意:

iterateF :: Int -> (a -> a) -> (a -> a)
iterateF n = foldr (.) id . replicate n
正如您所看到的,在Wikipedia定义和这里提供的解决方案中都没有主题函数参数的概念。它是另一个函数上的函数,即主题函数被视为一个值。与涉及主题函数参数的实现相比,这是解决问题的更高级别的方法

现在,关于你对中间列表的担忧。从源代码的角度来看,该解决方案与@jmcejuela发布的Scala解决方案非常相似,但有一个关键区别是GHC optimizer完全抛弃了中间列表,将函数转换为主题函数上的简单递归循环。我不认为它可以得到更好的优化


为了自己轻松地检查中间编译器结果,我建议使用。

尽管这没有jmcejuela的答案(我更喜欢)那么简洁,但在scala中,有另一种方法可以在没有
函数
模块的情况下表达这样的函数。当n=0时,它也起作用

def iterate[T](f: T=>T, n: Int) = (x: T) => (1 to n).foldLeft(x)((res, n) => f(res))
为了克服创建列表的困难,可以使用显式递归,反之则需要更多的静态类型

def iterate[T](f: T=>T, n: Int): T=>T = (x: T) => (if(n == 0) x else iterate(f, n-1)(f(x)))
有一种使用模式匹配的等效解决方案,类似于Haskell中的解决方案:

iterateF 0 _ = id
iterateF n f = f . iterateF (n - 1) f
def iterate[T](f: T=>T, n: Int): T=>T = (x: T) => n match {
  case 0 => x
  case _ => iterate(f, n-1)(f(x))
}
最后,我更喜欢用Caml编写它的简短方式,在这里根本不需要定义变量的类型

let iterate f n x = match n with 0->x | n->iterate f (n-1) x;;
let f5 = iterate f 5 in ...
我最喜欢pigworker/tauli的想法,但因为他们只是发表评论,所以我用它来回答。

\n fx->迭代fx!!N

\n f->(!!n)。迭代f
甚至可能:

\n->(!!n.)。迭代

使用
迭代的东西
,也许?@pigworker iterate看起来不错<代码>\n f x->迭代f x!!n应该有效。
直到((fy,k-1))(x,n)
。目前,
直到
仍然是递归的,所以它不会被内联,你也不会得到
f
的拆箱和内联,但是在头部,它已经被工作者包装器转换,当这个更改被释放时,编译器会为你编写循环。请将你的注释转换成答案,这样我们就可以投票给他们了。有趣吗ght(您可能已经知道):这正是工作原理。一个数
n
被编码为一个函数,它将自身的参数组成
n
次。是否有任何东西可以通过二进制策略获得,类似于在求幂中使用的策略?将
f.f.f.f
作为
g.g
其中
g=f.f
?减少迭代次数。可能不符合ter.@benw:当然,这会减少要计算的
(.)
的数量,就像求幂法一样。如果你编译一个精心设计的示例而不进行优化,你甚至可以测量性能差异!