سؤال

I want to write the following code:

let someAsync () = async {
    if 1 > 2 then return true // Error "this expression is expected to have type unit ..."
    // I want to place much code here    
    return false
}

F# for some reason thinks that I need to write it like that:

let someAsync () = async {
    if 1 > 2 then return true
    else
        // Much code here (indented!)
        return false
}

In latter case no error message is produced. But in my view both pieces of code are equivalent. Is there any chance I could avoid unnecessary nesting and indentation?

UPD. What I am asking is possible indeed! Please take a look at example, see section Real world example

I will quote the code:

let validateName(arg:string) = imperative {
    if (arg = null) then return false  // <- HERE IT IS
    let idx = arg.IndexOf(" ")
    if (idx = -1) then return false    // <- HERE IT IS

    // ......
    return true 
}

So, it is possible, the only question is if it is possible to implement somehow in async, via an extension to module or whatever.

هل كانت مفيدة؟

المحلول 2

There is an important difference between the async computation builder and my imperative builder.

In async, you cannot create a useful computation that does not return a value. This means that Async<'T> represents a computation that will eventually produce a value of type 'T. In this case, the async.Zero method has to return unit and has a signature:

async.Zero : unit -> Async<unit>

For imperiatve builder, the type Imperative<'T> represents a computation that may or may not return a value. If you look at the type declaration, it looks as follows:

type Imperative<'T> = unit -> option<'T>

This means that the Zero operation (which is used when you write if without else) can be computation of any type. So, imperative.Zero method returns a computation of any type:

imperative.Zero : unit -> Imperative<'T>

This is a fundamental difference which also explains why you can create if without else branch (because the Zero method can create computation of any type). This is not possible for async, because Zero can only create unit-returning values.

So the two computations have different structures. In particular, "imperative" computations have monoidal structure and async workflows do not. In more details, you can find the explanation in our F# Computation Zoo paper

نصائح أخرى

I think that situation is described here: Conditional Expressions: if... then...else (F#)

(...) if the type of the then branch is any type other than unit, there must be an else branch with the same return type.

Your first code does not have else branch, which caused an error.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top