Как создать новую область, используя let в F #? - PullRequest
6 голосов
/ 24 марта 2009

Я пытаюсь инициализировать XmlDocument в F #, не загрязняя глобальное пространство имен - мой единственный функциональный фон исходит от LISP, где можно создать новую область видимости, используя «let». Я придумал это:

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

Я был довольно удивлен, когда мое первое решение не сработало:

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

print_any reader.ToString // Still in scope!

Какой предпочтительный способ делать то, что я хочу?

Ответы [ 3 ]

3 голосов
/ 24 марта 2009

кажется, что когда вы используете «let .. in», вы можете переопределить настройку «#light» по умолчанию, которая заключается в том, что пробел является значительным, поэтому я думаю, что именно так и происходит в этом случае, и почему вы не получаете никаких предупреждений / ошибка во втором случае (вы добавили 'in', поэтому компилятор считает, что вы хотите явно указать область действия). Это кажется немного странным, так что это может быть ошибкой. Я уверен, что Брайан из команды F # скоро ответит на это сомнение: -).

В любом случае, я думаю, что компилятор обрабатывает ваш второй пример так же (используя более простой пример компиляции):

open System

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

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

Вы можете заставить его обращаться с ним так, как вам хочется, если вы добавите скобки и напишите что-то вроде этого:

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

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

В общем, вы можете использовать скобки для указания областей в любом месте программы F #. Например, вы можете написать:

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

В этом примере выводится «10», а затем «1». Конечно, это не кажется очень практичным, но это полезно при использовании ключевого слова use, которое ведет себя как let, но работает для объектов IDisposable и гарантирует, что объект удаляется, когда покидает область видимости. (это как using в C #):

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

EDIT : Я совершенно забыл упомянуть важный момент - первый способ написания кода кажется мне более естественным (и он полностью использует преимущества «простого» синтаксиса #light, предлагаемого F #), поэтому я бы предпочел его :-).

2 голосов
/ 24 марта 2009

Ваш первый пример - стиль, принятый Доном Саймом и остальными энтузиастами F #. Смешивание #light и ML-style let .. in не кажется хорошей идеей.

Вы можете прочитать некоторые образцы из Expert F # , чтобы почувствовать современный стиль F #.

Существуют также Соглашения о форматировании F # , написанные Доном Саймом.

0 голосов
/ 26 марта 2009

Часть проблемы может заключаться в том, что «let ... in ...» является выражением, а не утверждением, поэтому использование этой конструкции на верхнем уровне в действительности не имеет смысла. Например, что бы это значило сказать:

let x = 1 in
  x - 5

на верхнем уровне? Похоже, что компилятор должен пометить любое использование «let ... in ...» на верхнем уровне как ошибку.

Другая проблема заключается в том, что API XmlDocument не написан в функциональном стиле (вообще), что делает его немного неудобным для использования из F #. Я бы сказал, что ваша первая попытка примерно так же хороша, как и вы, но было бы неплохо, если бы API позволял что-то вроде:

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

или если был конструктор для XmlDocument, который принимал XmlReader, но, поскольку API является непреложно обязательным, вам придется сделать это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...