7 votes

Comment créer un nouveau scope en utilisant let en F# ?

J'essaie d'initialiser un XmlDocument en F#, sans polluer l'espace de noms global - ma seule expérience fonctionnelle vient du LISP, où l'on peut créer un nouveau scope en utilisant "let". J'en suis arrivé à ceci :

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

J'ai été assez surpris de voir que ma première solution ne fonctionnait pas :

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

print_any reader.ToString // Still in scope!

Quelle est la meilleure façon de faire ce que je veux ?

4voto

Tomas Petricek Points 118959

Il semble que lorsque vous utilisez "let .. in" vous pouvez outrepasser le paramètre par défaut de "#light" qui est que les espaces blancs sont significatifs, donc je suppose que c'est ce qui se passe dans ce cas et pourquoi vous n'obtenez pas d'avertissement/erreur dans le second cas (vous avez ajouté 'in', donc le compilateur pense que vous voulez spécifier la portée explicitement). Cela semble un peu bizarre et il s'agit peut-être d'un bogue. Je suis sûr que Brian de l'équipe F# répondra bientôt à ce doute :-).

Quoi qu'il en soit, je pense que le compilateur traite votre deuxième exemple de la même manière (en utilisant un exemple plus facile à compiler) :

open System

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

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

Vous pouvez le forcer à le traiter comme vous le souhaitez en ajoutant des parenthèses et en écrivant quelque chose comme ceci :

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

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

En général, vous pouvez utiliser des parenthèses pour spécifier des scopes à n'importe quel endroit du programme F#. Par exemple, vous pouvez écrire :

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

Cet exemple imprime "10" puis "1". Bien sûr, cela ne semble pas très pratique, mais c'est utile lorsque l'on utilise la fonction use qui se comporte comme un mot-clé let mais fonctionne pour IDisposable et s'assure que l'objet est éliminé lorsqu'il quitte le champ d'application (c'est comme pour les objets 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 : J'ai complètement oublié de mentionner le point important - la première façon d'écrire le code me semble plus naturelle (et elle utilise pleinement les avantages de la syntaxe #light "simple" qu'offre F#), donc je la préférerais :-).

2voto

Frank Krueger Points 27508

Votre premier exemple semble être le style adopté par Don Syme et le reste des enthousiastes de F#. Le mélange #light et le style ML let .. in ne semble pas être une bonne idée.

Vous pouvez lire quelques exemples de Expert F# pour se faire une idée du style de F# contemporain.

Il y a aussi les Conventions de formatage F# écrit par Don Syme.

0voto

kvb Points 35490

Une partie du problème réside peut-être dans le fait que "let ... in ..." est une expression, et non une déclaration, de sorte que l'utilisation de cette construction au niveau supérieur n'a pas vraiment de sens. Par exemple, qu'est-ce que cela signifierait de dire :

let x = 1 in
  x - 5

au plus haut niveau ? Il semble que le compilateur devrait signaler toute utilisation de "let ... in ..." au niveau supérieur comme une erreur.

L'autre problème est que l'API XmlDocument n'est pas écrite dans un style fonctionnel (du tout), ce qui la rend un peu difficile à utiliser à partir de F#. Je dirais que votre première tentative est à peu près aussi bonne que vous allez l'être, mais ce serait vraiment bien si l'API permettait quelque chose de plus comme :

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

ou s'il existait un constructeur pour XmlDocument qui prenne un XmlReader, mais comme l'API est résolument impérative, vous devrez vous en contenter.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X