Consuming input line-by-line until the end is often useful. In C# I would write the following loop:
while ((line = Console.ReadLine()) != null) {
// ...
I wanted to do this using "idiomatic" F# (which to me includes avoiding let mutable
) and I came up with this:
let rec readlines = seq {
let line = Console.ReadLine()
if line <> null then
yield line
yield! readlines
}
The last line shows the following warning
Warning FS0040: This and other recursive references to the object(s) being defined will be checked for initialization-soundness at runtime through the use of a delayed reference. This is because you are defining one or more recursive objects, rather than recursive functions. This warning may be suppressed by using '#nowarn "40"' or '--nowarn:40'.
The warning would suggest I am actually not writing idiomatic F# (as warnings usually point out problematic code). Is there a better way to write the function that avoids the warnings?
2 Answers 2
What you have there is a value, but you probably want it to be a function:
let rec readlines () = seq {
let line = Console.ReadLine()
if line <> null then
yield line
yield! readlines ()
}
-
\$\begingroup\$ was this meant to be
yield line
instead ofyield v
? There is a pending edit on this post by another user making the change toyield line
and I want to make sure before accepting it. \$\endgroup\$Dan– Dan2015年07月10日 16:59:01 +00:00Commented Jul 10, 2015 at 16:59 -
\$\begingroup\$ In Visual Studio 2012, I'm getting a type constraint mismatch on the
yield! readlines ()
line. Any thoughts as to why? \$\endgroup\$octopusgrabbus– octopusgrabbus2016年09月22日 17:34:45 +00:00Commented Sep 22, 2016 at 17:34 -
\$\begingroup\$ @octopusgrabbus What does the error message say? \$\endgroup\$Mark Seemann– Mark Seemann2016年09月22日 17:41:43 +00:00Commented Sep 22, 2016 at 17:41
-
\$\begingroup\$ Must have been a weird alignment thing. The error is gone. Thanks for inquiring. \$\endgroup\$octopusgrabbus– octopusgrabbus2016年09月22日 17:44:54 +00:00Commented Sep 22, 2016 at 17:44
Mark's response does answer as to the warning you received.
An alternate approach could be
Seq.initInfinite // (1)
(fun _ -> Console.ReadLine())
|> Seq.takeWhile (fun line -> line <> null) // (2)
Edit: Could be restructured and more succinct as
fun _ -> Console.ReadLine()
|> Seq.initInfinite // (1)
|> Seq.takeWhile ((<>) null) // (2) (3)
-
1\$\begingroup\$ Thanks for a very helpful alternative. I was also searching for a non-recursive function example using the
Seq
methods. \$\endgroup\$octopusgrabbus– octopusgrabbus2016年09月22日 18:26:39 +00:00Commented Sep 22, 2016 at 18:26
Explore related questions
See similar questions with these tags.
()
addition in @MarkSeeman's answer. \$\endgroup\$