Прежде всего, я думаю, что это не правда, что «концепция, которая больше относится к объектно-ориентированному миру, является исключением» . Исключения существуют во многих функциональных языках семейства ML, и, например, OCaml довольно сильно полагается на них и использует их даже для определенных структур потоков управления. В F # это не так, потому что .NET-исключения несколько медленнее, но я вижу исключения, очень ортогональные к объектно-ориентированной / функциональной проблеме.
По этой причине я нахожу исключения, часто более предпочтительными, чем типы опций в F #. Недостатком является то, что меньше проверок типов (вы не знаете, что может генерировать), но есть и то, что язык обеспечивает хорошую встроенную поддержку языков для исключений. Если вам нужно обработать исключительные ситуации, исключения - хороший способ сделать это!
Чтобы ответить на ваш первоначальный вопрос о синтаксических уловках, которые вы можете сделать - я, вероятно, просто использовал бы функцию, как ваш существующий код, потому что это явно и легко понять (и, вероятно, вам понадобится только перенос исключений в некоторых основных функциях что вы реализуете).
Тем не менее, вы можете определить конструктор выражений вычислений, который оборачивает код в тело и служит в качестве вашей catchAll
функции с несколько более точным синтаксисом:
type CatchAllBuilder() =
member x.Delay(f) = try Some(f()) with _ -> None
member x.Return(v) = v
let catchAll = CatchAllBuilder()
Это позволяет вам написать что-то вроде:
catchAll { return Array.empty.[0] }
Как упоминалось ранее, я бы не стал этого делать, потому что (i) я не думаю, что все исключения должны быть преобразованы в опции в F #, и (ii) он вводит незнакомый синтаксис, который могут делать новые члены команды (и будущие вы) быть сбитым с толку, но это, вероятно, самый хороший синтаксис, который вы можете получить.
[РЕДАКТИРОВАТЬ: Теперь рабочая версия с return
- это несколько менее красиво, но, возможно, все еще полезно!]