Использование let! внутри операторов совпадения вызывает ошибку компиляции
Есть ли какое-то ограничение на использование let! внутри матчей? Я не уверен, почему это не будет компилироваться.
module Foo =
let Bar =
async {
let result =
match 1 with
| 1 ->
let! num = async.Return 12345 // Doesn't compile
1
| _ -> 2
return result
}
Сбой компиляции с помощью "Эта конструкция может использоваться только в выражениях вычислений"
Ответы
Ответ 1
Как уже объяснялось, проблема в том, что асинхронные рабочие процессы допускают только определенные типы вложений - вы не можете использовать let!
внутри обычного выражения, но только внутри выражения вычисления. Проблема в вашем примере на самом деле не является match
, а let
(которая содержит match
). Чтобы лучше понять, что происходит, спецификация выглядит (примерно) следующим образом:
cexpr: = let! x = expr в cexpr
| let x = expr в cexpr
| return! expr
| (...)
Главное, что аргумент является просто обычным выражением expr
, а тело, следующее за let
или let!
, является другим выражением вычисления, которое может содержать больше асинхронных операций.
Итак, если у вас есть let x = e1 in e2
, вы можете иметь let!
только в e2
, но не в e1
.
На практике вы можете делать то, что предлагает Дэниел, и использовать вложенный асинхронный рабочий процесс, или вы можете переписать свой код так, чтобы код, который должен быть асинхронным, не использовал ожидания внутри выражений там, где это невозможно - трудно сказать как это сделать вообще, но в вашем конкретном примере вы можете просто написать:
let bar = async {
match 1 with
| 1 ->
let! num = async.Return 12345
return 1
| _ ->
return 2 }
Ответ 2
Вызовы Bind
(через let!
) должны отображаться на верхнем уровне выражения вычисления. Вы можете исправить это, создав вложенный блок async { }
:
module Foo =
let Bar =
async {
let result = async {
match 1 with
| 1 ->
let! num = async.Return 12345
return 1
| _ -> return 2
}
return result
}
Ответ 3
Это сложно, потому что async в F # только вроде async в С#. В F # это не ключевое слово, это экземпляр Вычисление выражения. Операторы bang (!) [Let!; Do!, и т.д.] Работают только в блоках вычислений. То есть, они работают только для кода сразу под фигурными фигурными скобками. Когда вы выполняете совпадение, как вы это сделали, вы создали анонимный метод, который ничего не знает о выражении вычисления.
Как и ключевое слово С# wait, пусть! оператор отделяет код перед оператором от кода после оператора в отдельные методы. Я подозреваю, что код перед выпуском! оператор должен быть в состоянии полностью расслабиться от стека, и это ваша проблема здесь. Выражение "let result =" должно быть разрешено и не может, если у нас есть "let!" в середине его.
Я надеюсь, что это поможет.