我如何知道函数在F#中是否为尾递归

编程入门 行业动态 更新时间:2024-10-10 01:18:02
本文介绍了我如何知道函数在F#中是否为尾递归的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我写了下面的函数:

let str2lst str = let rec f s acc = match s with | "" -> acc | _ -> f (s.Substring 1) (s.[0]::acc) f str []

我怎么知道F#编译器是否将其变成了循环?是否有一种方法可以不使用Reflector(我没有Reflector的经验,也不了解C#)进行查找?

How can I know if the F# compiler turned it into a loop? Is there a way to find out without using Reflector (I have no experience with Reflector and I Don't know C#)?

另外,是否可以在不使用内部函数的情况下编写尾部递归函数,还是必须将循环驻留在其中?

Also, is it possible to write a tail recursive function without using an inner function, or is it necessary for the loop to reside in?

此外,F#std lib中是否有一个函数可以多次运行给定的函数,每次给它最后一个输出作为输入?可以说我有一个字符串,我想在该字符串上运行一个函数,然后在生成的字符串上再次运行它,依此类推...

Also, Is there a function in F# std lib to run a given function a number of times, each time giving it the last output as input? Lets say I have a string, I want to run a function over the string then run it again over the resultant string and so on...

推荐答案

不幸的是,没有简单的方法.

Unfortunately there is no trivial way.

阅读源代码并使用类型并通过检查来确定某项是否为尾调用(不是最后一件事",而不是在"try"块中)并不是很困难,但是人们会第二次-猜测自己并犯错误.没有简单的自动化方法(例如,检查生成的代码除外).

It is not too hard to read the source code and use the types and determine whether something is a tail call by inspection (is it 'the last thing', and not in a 'try' block), but people second-guess themselves and make mistakes. There's no simple automated way (other than e.g. inspecting the generated code).

当然,您可以在大量测试数据上尝试一下功能,看看它是否崩溃了.

Of course, you can just try your function on a large piece of test data and see if it blows up or not.

F#编译器将为所有尾部调用生成.tail IL指令(除非使用了将其关闭的编译器标志-用于当您要保留堆栈帧进行调试时使用),但直接尾部递归函数除外将被优化成循环.(我认为,如今,F#编译器在可以证明没有通过此调用站点进行递归循环的情况下,也无法发出.tail;这是一种优化,因为.tail操作码在许多平台上都稍慢一些.)

The F# compiler will generate .tail IL instructions for all tail calls (unless the compiler flags to turn them off is used - used for when you want to keep stack frames for debugging), with the exception that directly tail-recursive functions will be optimized into loops. ( I think nowadays the F# compiler also fails to emit .tail in cases where it can prove there are no recursive loops through this call site; this is an optimization given that the .tail opcode is a little slower on many platforms.)

'tailcall'是保留关键字,其思想是F#的未来版本可能允许您编写例如.

'tailcall' is a reserved keyword, with the idea that a future version of F# may allow you to write e.g.

tailcall func args

,如果不是尾声,则得到警告/错误.

and then get a warning/error if it's not a tail call.

只有不是自然地尾部递归(因此需要额外的累加器参数)的函数才会迫使"您进入内部函数"惯用语.

Only functions that are not naturally tail-recursive (and thus need an extra accumulator parameter) will 'force' you into the 'inner function' idiom.

以下是您所要求的代码示例:

Here's a code sample of what you asked:

let rec nTimes n f x = if n = 0 then x else nTimes (n-1) f (f x) let r = nTimes 3 (fun s -> s ^ " is a rose") "A rose" printfn "%s" r

更多推荐

我如何知道函数在F#中是否为尾递归

本文发布于:2023-11-29 18:47:33,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1647292.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:递归   函数

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!