2009-03-24 11 views
6

Estoy tratando de inicializar un XmlDocument en F #, sin contaminar el espacio de nombres global; mi único fondo funcional proviene de LISP, donde se puede crear un nuevo ámbito usando "let". Se me ocurrió esto:Cómo crear un nuevo ámbito usando let in F #?

let doc = 
    let reader = new XmlTextReader("url") 
    let doc = new XmlDocument() 
    doc.Load(reader) 
    doc 

cuál fue mi sorpresa cuando mi primera solución no funcionó:

let doc = new XmlDocument() in 
    let reader = new XmlTextReader("url"); 
    doc.Load(reader) 

print_any reader.ToString // Still in scope! 

¿Cuál es la mejor forma de hacer lo que quiero?

+1

Guau bueno. Si Brian no responde a este, debería considerar enviarlo a fsbugs @ microsoft.com. – MichaelGG

+0

Abrí el error 4693. :) Evite "dejar ... entrar" en el código #light. – Brian

Respuesta

3

Parece que cuando usa "dejar ... entrar" puede anular la configuración predeterminada "#light", que es que el espacio en blanco es significativo, así que supongo que eso es lo que sucede en este caso y por qué no recibe advertencia/error en el segundo caso (agregaste 'in', por lo que el compilador cree que deseas especificar el alcance explícitamente). Parece un poco raro, así que puede ser un error. Estoy seguro de que Brian del equipo F # responderá a esta duda pronto :-).

De todos modos, creo que el compilador trata de su segundo ejemplo del mismo modo (usando un más fácil de compilar ejemplo):

open System 

let ar = new ResizeArray<_>() in 
let rnd = new Random();  
ar.Add(rnd.Next()) 

printfn "%A" (rnd.Next()) 

Usted puede obligarlo a tratarlo como lo hubiera querido si se agrega entre paréntesis y escribir algo como esto:

let ar = new ResizeArray<_>() in 
    (let rnd = new Random() 
    ar.Add(rnd.Next())) 

printfn "%A" (rnd.Next()) 

En general, puede usar paréntesis para especificar ámbitos en cualquier lugar del programa F #. Por ejemplo, puede escribir:

let a = 1 
(let a = a + 10 
printfn "%d" a) 
printfn "%d" a 

Este ejemplo imprime "10" y luego "1". Por supuesto, esto no parece ser muy práctico, pero es útil cuando se usa la palabra clave use que se comporta como let, pero funciona para los objetos IDisposable y asegura que el objeto se elimina cuando sale del ámbito (esto es como using en C#):

let some = new Some() 
(use file = new StreamReader(...) 
let txt = file.ReadToEnd() 
printfn "%s" txt) 
doSomething() // continue, 'file' is now closed! 

EDITAR: me olvidó por completo mencionar el importante bits - la primera forma de escribir el código parece más natural para mí (y utiliza plenamente los beneficios de #Light "simple" sintaxis que F # ofrece), así que lo preferiría :-).

2

Su primer ejemplo parece ser el estilo adoptado por Don Syme y el resto de entusiastas de F #. Mezclar #light y ML-style let .. in no parece una buena idea.

Puede leer algunas muestras de Expert F# para tener una idea del estilo F # contemporáneo.

También están los F# Formatting Conventions escritos por Don Syme.

+0

De hecho, no es necesario utilizar la opción dejar .. con la opción #, aunque al mirar la especificación sigue siendo válida como sintaxis opcional. El hecho de que el lector todavía está en el alcance parece ser muy extraño para mí. Posible error, tal vez? – Noldorin

+0

En mi opinión, parece un error. Pero él está mezclando mucho en ese ejemplo: #light, the ';' operador, sangría, y 'en'. La sintaxis de F # está lejos de ser elegante, y no es intuitiva: demasiado exceso de equipaje como resultado de la fusión de ML y .NET ... –

0

Parte del problema puede ser que "let ... in ..." es una expresión, no una declaración, por lo que usar esta construcción en el nivel superior no tiene sentido. Por ejemplo, ¿qué significa decir:

let x = 1 in 
    x - 5 

en el nivel superior? Parece que el compilador debe marcar cualquier uso de "let ... in ..." en el nivel superior como un error.

El otro problema es que la API de XmlDocument no está escrita en un estilo funcional (en absoluto), lo que hace que sea un poco difícil de usar desde F #.Yo diría que su primer intento es casi tan bueno como se va a conseguir, pero seguro que sería bueno si el API permitió algo más parecido a:

let doc = 
    let reader = new XmlTextReader("url") 
    reader.ReadAsDocument() 

o si había un constructor para XmlDocument que tuvo un XmlReader, pero como la API es absolutamente imprescindible, tendrás que conformarte.

Cuestiones relacionadas