I am trying to initialize an XmlDocument in F#, without polluting the global namespace - my only functional background comes from LISP, where one can create a new scope using "let". I came up with this:
let doc =
let reader = new XmlTextReader("url")
let doc = new XmlDocument()
doc.Load(reader)
doc
I was rather surprised when my first solution didn't work:
let doc = new XmlDocument() in
let reader = new XmlTextReader("url");
doc.Load(reader)
print_any reader.ToString // Still in scope!
What is the preferred way to do what I want?
let allows you to declare variables that are limited to the scope of a block statement, or expression on which it is used, unlike the var keyword, which declares a variable globally, or locally to an entire function regardless of block scope.
In JavaScript, scopes are created by code blocks, functions, modules. While const and let variables are scoped by code blocks, functions or modules, var variables are scoped only by functions or modules. Scopes can be nested. Inside an inner scope you can access the variables of an outer scope.
let is block scoped Anything within curly braces is a block. We see that using hello outside its block (the curly braces where it was defined) returns an error. This is because let variables are block scoped .
The let keyword is used to declare variables in JavaScript. The var keyword can also be used to declare variables, but the key difference between them lies in their scopes. var is function scoped while let is block scoped - we will discuss this in more detail later.
it seems that when you use "let .. in" you can override the default "#light" setting which is that whitespace is significant, so I guess that's what happens in this case and why you don't get any warning/error in the second case (you added 'in', so the compiler thinks that you want to specify the scope explicitly). It seems a bit weird so it may be a bug. I'm sure Brian from the F# team will answer this doubt soon :-).
Anyway, I think the compiler treats your second example just as (using an easier to compile example):
open System
let ar = new ResizeArray<_>() in
let rnd = new Random();
ar.Add(rnd.Next())
printfn "%A" (rnd.Next())
You can force it to treat it as you wanted if you add parentheses and write something like this:
let ar = new ResizeArray<_>() in
(let rnd = new Random()
ar.Add(rnd.Next()))
printfn "%A" (rnd.Next())
In general, you can use parentheses to specify scopes in any place of the F# program. For example you can write:
let a = 1
(let a = a + 10
printfn "%d" a)
printfn "%d" a
This example prints "10" and then "1". Of course, this doesn't seem to be very practical, but it is useful when using the use
keyword that behaves like let
, but works for IDisposable
objects and ensures that the object is disposed when it leaves the scope (this is just like using
in C#):
let some = new Some()
(use file = new StreamReader(...)
let txt = file.ReadToEnd()
printfn "%s" txt)
doSomething() // continue, 'file' is now closed!
EDIT: I completely forgot to mention the important bit - the first way of writing the code seems more natural to me (and it fully uses the benefits of "simple" #light syntax that F# offers), so I would prefer it :-).
Your first example seems to be the style adopted by Don Syme and the rest of the F# enthusiasts. Mixing #light
and ML-style let .. in
doesn't seem like a good idea.
You can read some samples from Expert F# to get a feel for contemporary F# style.
There are also the F# Formatting Conventions written by Don Syme.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With