A functional take on console program loop in F#
Often when learning a new technology I start with a simple console application in which the program is run in a loop it continues to prompt you for more input until you give some command like quit or exit or whatever you choose:
Enter input: someInput
someOutput
Enter input: otherInput
someoutPut
Enter input: quit
Thanks! Come again!
The code for this is in an imperative language is usually something like:
1: while(true)
2: {
3: Console.Write("\nEnter input:");
4: var line = Console.ReadLine();
5: if(line == "quit") break;
6:
7: doSomething(line);
8: }
9:
10: Console.WriteLine("Thanks! Come Again");
While reading some F# samples, I saw some code doing essentially the same thing which looked something like:
1: Console.Write "\nEnter input:"
2: let mutable input = Console.ReadLine()
3: while input <> "quit"
4: do
5:
6: if input <> "quit"
7: then
8: doSomething input
9: Console.Write "\nEnter input:"
10: input <- Console.ReadLine()
Now this just feels dirty! In a functional language explicit loop constructs like a while loop feel wrong. I different way of doing this which is more functional is to create an infinite list of actions. Where each action represents one iteration of any of the above loops. Then you just execute each action until some condition is met (like seeing the input “quit”).
1: let action = fun _ ->
2: Console.Write "\nEnter input: "
3: Console.ReadLine()
4:
5: let readlines = Seq.init_infinite (fun _ -> action())
6:
7: let run item = if item = "quit"
8: then Some(item)
9: else
10: parse item
11: None
12:
13: Seq.first run readlines |> ignore
14: Console.WriteLine "Thanks! Come Again"
This code makes use of the Seq.init_infinite which create a infinite sequence and Seq.first which enumerates the sequence until the passed in function returns Some.
Comments
- Anonymous
April 15, 2009
You've been kicked (a good thing) - Trackback from DotNetKicks.com