Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a new scope using let in F#?

Tags:

syntax

f#

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?

like image 984
Michał Bendowski Avatar asked Mar 24 '09 00:03

Michał Bendowski


People also ask

What is the scope of let keyword?

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.

How is a new scope created in JavaScript?

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.

Is Let scoped?

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 .

Is let function scope in JavaScript?

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.


2 Answers

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 :-).

like image 152
Tomas Petricek Avatar answered Oct 24 '22 11:10

Tomas Petricek


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.

like image 34
Frank Krueger Avatar answered Oct 24 '22 13:10

Frank Krueger