Reputation: 43
I can have a function like this:
let readLines (filePath:string) = [
use sr = new StreamReader (filePath)
while not sr.EndOfStream do
yield sr.ReadLine ()
]
But I cannot have a function like this:
let lines (f:string) =
let readLines (filePath:string) = [
use sr = new StreamReader (filePath)
while not sr.EndOfStream do
yield sr.ReadLine ()
] in readLines f
I get the error:
Block following this 'let' is unfinished. Expect an expression.
I cannot wrap my head around this error. I would expect a list of string from 'lines'.
Upvotes: 4
Views: 168
Reputation: 243041
The minimal change to make your second snippet compile is to insert two (or one) more space before the closing square bracket:
let lines (f:string) =
let readLines (filePath:string) = [
use sr = new StreamReader (filePath)
while not sr.EndOfStream do
yield sr.ReadLine ()
] in readLines f
The reason is that the body of a let
binding needs to be indented further than the let
keyword - the F# compiler uses this to determine where the body expression of the function ends. This is also what the error message is trying to say "this 'let' is unfinished" almost always means that you do not have a valid expression inside let
.
As @kvb mentioned in a comment, a more idiomatic way of writing this is to fully rely on the fact that the F# compiler is whitespace-sensitive and will infer where the in
keywords are in correctly indented code. My personal preference is to also put [
on a new line:
let lines (f:string) =
let readLines (filePath:string) =
[ use sr = new StreamReader (filePath)
while not sr.EndOfStream do
yield sr.ReadLine () ]
readLines f
Upvotes: 4