Конструкции обработки исключений F#

почему F# не поддерживает блок try/with/finally?

это не имеет смысла попробовать нечто, интернет С любым исключением, которое он бросает, по крайней мере, для регистрации исключения, а затем обязательно что код выполняется после всего этого?

конечно, мы можем сделать

try
    try
        ...
    with ex -> ...
finally
    ...

но это кажется слишком искусственным, это ясно демонстрирует, что "F# против try/with/finally". Почему так?

5 ответов


как кто-то уже упоминал, вы обычно используете try-with-finally чтобы убедиться, что вы правильно освободить все ресурсы, в случае исключение. Я думаю, что в большинстве случаев вы можете сделать это более легко с помощью use ключевые слова:

let input = 
  try
    use stream = new FileStream("C:\temp\test.txt");
    use rdr = new StreamReader(stream);
    Some(rdr.ReadToEnd())
  with :? IOException as e -> 
    logError(e)
    None

Я думаю, что это в основном причина, почему вам не нужен try-with-finally так же часто, как и в других языках. Но, конечно, есть некоторые ситуации, когда вам это может понадобиться (но вы могли бы, конечно, избежать этого, создав экземпляр IDisposable используя выражения объекта (что синтаксически очень просто). Но я думаю, что это настолько редко, что команде F# действительно не нужно беспокоиться об этом.


ортогональность? Вы можете просто вложить попытку-с внутренней попыткой-наконец, как вы показываете. (Это то, что происходит на уровне IL в любом случае, я думаю.)

тем не менее, try-with-finally-это то, что мы можем рассмотреть в будущей версии языка.

лично я только столкнулся с желанием этого пару раз, но когда вам это нужно, это немного беспокоит, чтобы сделать дополнительную вложенность/отступ. В общем, я обнаружил, что редко пишу код обработки исключений, и это, как правило, только один или другой (например, окончательно восстановить инвариантную или другую транзакционную семантику или "поймать" в верхней части приложения, чтобы зарегистрировать исключение или показать диагностику пользователя).

но я не думаю, что есть много, чтобы читать в отношении дизайна здесь.


Не вдаваясь в подробности, потому что большие детали в

эксперт .NET 2.0 Il ассемблер Серж Лидин

См.: Ch. 14, Управляемая Обработка Исключений

наконец-то и ошибка обработчики не могут мирно сосуществовать с другими обработчиками, так что если охраняемом блоке наконец-то или ошибка обработчик, он не может есть ничего другого. Совместить наконец-то или ошибка обработчик с другими обработчиками, вам нужно вложить охраняемые и обработчики в другие охраняемые блоки ..., так что каждый наконец-то или ошибка handler имеет свой личный охраняемый блок."

pg. 300

a try / catch использует ошибка обработчик и try / finally использует наконец-то обработчик.

посмотреть: ILGenerator.BeginFaultBlock Метод

Если вы испускаете ошибка обработчик в блоке исключений, который также содержит catch обработчик, или наконец-то обработчик, полученный код непроверяемый.

Итак, все языки .net можно рассматривать как использование синтаксического surgar, и поскольку F# настолько Новый,они просто еще не реализовали его. Никакого вреда ни фоулд.


Я уточню свой комментарий в этом ответе.

  1. Я есть нет причин предполагать, что вы хотите поймать исключения и завершить некоторые ресурсы на том же уровне. Возможно, вы привыкли делать это таким образом на языке, на котором было удобно обращаться с обоими одновременно, но это совпадение, когда это происходит. Завершение удобно, когда вы не улавливаете все исключения из внутреннего блока. try...with для ловли исключения, чтобы вычисления могли продолжаться нормально. Между ними просто нет никакой связи (во всяком случае, они идут в противоположных направлениях: вы ловите исключение или позволяете ему пройти?).

  2. почему вы вообще должны что-то завершать? Не ГК будет управлять неиспользуемые ресурсы? Ах... но язык пытается предоставить вам доступ к системным примитивам, которые работают с побочными эффектами, с явными распределениями и де-распределений. Вы должны отменить выделение того, что вы выделили (во всех случаях)... Разве вы не должны обвинять гнилой интерфейс, который предоставляет система вместо F#, который в данном случае является только мессенджером?


но это кажется слишком искусственным, это ясно демонстрирует, что "F# против try/with/finally". Почему так?

Я думаю, что F# может быть" против " обработки исключений вообще. Ради совместимости .NET, он должен поддерживать их, но в основном,нет обработки исключений* в функциональном программировании.

исключение метания/ловли означает выполнение "прыжков в никуда", которые даже не замечаются системой типов, которая оба принципиально против функциональной философии.

вы можете использовать чисто функциональный (монадический) код для обертывания исключений. Все ошибки обрабатываются через значения, с точки зрения системы базового типа и без скачков/побочных эффектов.

вместо написания функции

let readNumber() : int = ...

это может вызвать произвольные исключения, вы просто укажете

let readNumber() : int option = ...

что делает этот пункт Автоматически ясным своей сигнатурой типа.

*Это это не означает, что мы не обрабатываем исключительные ситуации, это просто о том, как обработка исключений в .NET / C++.