How do you implement comefrom in F#?
I've begun to be accustomed to the F# way of implementing goto
control flow, but I'm not quite sure how I can han开发者_StackOverflow中文版dle comefrom
, a la INTERCAL.
comefrom
is a very useful construct that allows you to jump from a label. The following example program uses it to print the complete instructions for washing your hands:
comefrom repeat
Console.Write "Lather"
Console.Write "Rinse"
repeat
The beauty of comefrom
is that you can put a label in multiple places.
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
I tried both of these programs, but the capricious F# compiler decided to disappoint me. How can I take advantage of comefrom
in F#?
This is pretty close to the syntax you want.
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())
Once you wrap your head around a function, f
, accepting a function, g
, which itself is passed to f
, it's relatively straightforward.
Migrating INTERCAL code to F# is hard. This hopefully should reduce the work involved.
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()
?
I think that comefrom
corresponds to function declarations even better than goto
.
If you're doing something like
goto
in F#, then your label corresponds to function declaration and thegoto
command corresponds to function call. In case ofcomefrom
, thecomefrom
command corresponds to function declaration and the label corresponds to function call.
Using functions, your code looks like this (EDIT: which is the same thing as what Ramon already posted, but I'll keep the answer here, because it has additional explanation):
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()
If you really want to use syntax that resembles comefrom
command then take a look at the options below. However, I don't really see the point - if you're adapting some legacy code, then you'll have to translate many other things to F# and using a weird syntax will just make F# less idiomatic. There is no way to add a new real syntactic construct like comefrom
to F#.
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 ()
Alternatively, you could define comefrom
computation builder and then use the following syntax:
let rec restart = comefrom {
Console.Write "Do you want to restart this program?"
// (omitted)
return! restart() }
(This blog post gives a very simple example of computation builder that you could adapt)
精彩评论