Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using let! inside match statements causes compilation error

Tags:

f#

Is there some restriction on using let! inside match statements? I'm not sure why this won't compile.

module Foo =
  let Bar =
    async {      
      let result =
        match 1 with
        | 1 ->
          let! num = async.Return 12345 // Doesn't compile
          1
        | _ -> 2

      return result
    }

Compilation fails with "This construct may only be used within computation expressions"

like image 832
Oenotria Avatar asked Jan 03 '14 21:01

Oenotria


1 Answers

As already explained, the problem is that asynchronous workflows only allow certain kinds of nestings - you cannot use let! inside an ordinary expression, but only inside computation expression. The problem in your example is not really the match but the let (which contains match). To better see what's going on, the specification looks (roughly) as follows:

cexpr := let! x = expr in cexpr
           |  let x = expr in cexpr
           |  return! expr
           |  (...)

The key thing is that the argument is just an ordinary expression expr and the body following let or let! is another computation expression that can contain more asynchronous operations.

So, if you have let x = e1 in e2 then you can only have let! in e2 but not in e1.

In practice, you can do what Daniel suggests and use nested asynchronous workflow, or you can rewrite your code so that the code that needs to be asynchronous does not use waiting inside expressions where this is not possible - it is hard to say how to do this in general, but in your specific example, you can just write:

let bar = async {      
  match 1 with
  | 1 ->
      let! num = async.Return 12345 
      return 1
  | _ -> 
      return 2 }
like image 59
Tomas Petricek Avatar answered Nov 30 '22 23:11

Tomas Petricek