如何在F#中实现comefrom?

如何在F#中实现comefrom?,f#,comefrom,F#,Comefrom,我已经开始习惯了F#方式的控制流程,但我不太确定我能如何处理,a la comefrom是一个非常有用的结构,允许您从标签跳转。以下示例程序使用它打印洗手的完整说明: comefrom repeat Console.Write "Lather" Console.Write "Rinse" repeat comefrom的美妙之处在于,您可以在多个位置放置标签 comefrom restart Console.Write "Do you want to restart this program?

我已经开始习惯了F#方式的控制流程,但我不太确定我能如何处理,a la

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


我认为
comefrom
对应的函数声明甚至比
goto
更好

如果在F#中执行类似于
goto
的操作,则标签对应于函数声明,
goto
命令对应于函数调用。在
comefrom
的情况下,
comefrom
命令对应于函数声明,标签对应于函数调用

使用函数,您的代码如下所示(编辑:,这与Ramon已经发布的内容相同,但我将在这里保留答案,因为它有额外的解释):

如果您确实想使用类似于
comefrom
命令的语法,请查看下面的选项。然而,我并不真正明白这一点——如果你要修改一些遗留代码,那么你必须将许多其他东西翻译成F,而使用奇怪的语法只会让F变得不那么地道。没有办法向F#添加一个新的真正的语法结构,比如
comefrom

或者,您可以从计算生成器定义
come,然后使用以下语法:

let rec restart = comefrom {
  Console.Write "Do you want to restart this program?"
  // (omitted)
  return! restart() }

(这是一个非常简单的计算生成器示例,您可以对其进行调整)

这与您想要的语法非常接近

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#很难。这有望减少所涉及的工作量。

这是一个做同样事情的程序,但它不使用
comefrom
命令。我需要实现一个兼容的
comefrom
命令,这样我就不必完全重写旧代码。@彼得:你似乎在用一种与旧代码不同的语言编写代码——你希望不必重写其中的一些(如果不是全部的话)?@Peter祝你项目顺利:)完成后,请发布它(或其中的一部分)那么我们都来看看你是如何解决所有这些问题的。我想知道,你为什么坚持使用F#?它只是不是为了处理
goto
comefrom
而设计的。这让我想起了我的小实验“抽象尾部递归循环”:是的,看起来很相似。事实上,你可能也可以做同样的事情:
loop(*comefrom*)(有趣的循环->如果继续,然后循环()否则未选中。defaultof)
这对菜单系统可能很有用。你可以将它传递到另一个子菜单,而不是在最后调用restart。
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 ()
let rec restart = comefrom {
  Console.Write "Do you want to restart this program?"
  // (omitted)
  return! restart() }
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())