我已经习惯了implementing goto
控制流的F#方式,但我不太确定如何处理comefrom
,la INTERCAL。
comefrom
是一个非常有用的结构,允许您从标签跳转。以下示例程序使用它来打印洗手的完整说明:
comefrom repeat
Console.Write "Lather"
Console.Write "Rinse"
repeat
comefrom
的美妙之处在于你可以在多个地方贴上标签。
comefrom restart
Console.Write "Do you want to restart this program?"
let a = Console.ReadLine()
match a with
| "Y" -> restart
| _ -> Console.Write "Too bad! It will restart whether you like it or not!"
restart
我尝试了这两个程序,但反复无常的F#编译器决定让我失望。如何利用F#中的comefrom
?
答案 0 :(得分:5)
这非常接近您想要的语法。
let comefrom f =
let rec g = (fun () -> f g)
f g
comefrom (fun restart ->
Console.Write "Do you want to restart this program?"
let a = Console.ReadLine()
match a with
| "Y" -> restart()
| _ -> Console.Write "Too bad! It will restart whether you like it or not!"
restart())
一旦你绕过一个函数f
,接受一个函数g
,它本身被传递给f
,它就相对简单了。
将INTERCAL代码迁移到F#很难。这有望减少所涉及的工作。
答案 1 :(得分:3)
let rec restart() =
Console.Write "Do you want to restart this program?"
let a = Console.ReadLine()
match a with
| "Y" -> restart()
| _ -> Console.Write "Too bad! It will restart whether you like it or not!"
restart()
答案 2 :(得分:3)
我认为comefrom
对应的函数声明甚至比goto
更好。
如果您在F#中执行类似
goto
的操作,那么您的标签对应于函数声明,goto
命令对应于函数调用。在comefrom
的情况下,comefrom
命令对应于函数声明,标签对应于函数调用。
使用函数,您的代码看起来像这样(编辑: 这与Ramon已发布的内容相同,但我会在这里保留答案,因为它有其他解释< / em>的):
let rec restart() =
Console.Write "Do you want to restart this program?"
let a = Console.ReadLine()
match a with
| "Y" -> restart()
| _ -> Console.Write "Too bad! It will restart whether you like it or not!"
restart()
如果您真的想使用类似comefrom
命令的语法,请查看下面的选项。但是,我并没有真正看到这一点 - 如果你正在调整一些遗留代码,那么你将不得不将许多其他东西翻译成F#,并且使用一种奇怪的语法只会使F#不那么惯用。无法向F#添加新的真正的语法结构,如comefrom
。
let rec restart = comefrom (fun () ->
Console.Write "Do you want to restart this program?"
// (omitted)
restart())
// where 'comefrom' is just a trivial wrapper for a function
let comefrom f () = f ()
或者,您可以定义comefrom
计算构建器,然后使用以下语法:
let rec restart = comefrom {
Console.Write "Do you want to restart this program?"
// (omitted)
return! restart() }
(这个blog post给出了一个非常简单的计算构建器示例,可以适应)