Обработка ошибок

def try_read_file (path : String) : Result<String, String> =
    ...

object i32
    def try_parse (s : String) : Option<i32> =
        ...

Result<String, String> содержит либо прочитанный из файла текст в Ok<String>, либо Error<String> с сообщением об ошибке.

def try_add (lhs_path : String) (rhs : i32) =
    let lhs =
        let! text = try_read_file lhs_path
        let! number = i32.try_parse text
        number

    lhs + rhs |> Some

Привязки text и number имеют типы String и i32, учитывающие только случаи успешного выполнения функций try_read_file и try_parse.

Ниже показан аналогичный код без let!.

def try_add (lhs_path : String) (rhs : i32) =
    let lhs =
        let text = case try_read_file lhs_path of
            Result/Ok text -> text
            Result/Error _ -> return None

        let number = case i32.try_parse text of
            Some number -> number
            None -> return None

        number

    lhs + rhs |> Some

Полученное от try_read_file сообщение об ошибке можно передать выше по стеку вызовов, вернув Result<i32, String> из try_add вместо Option<i32>.

def try_add (lhs_path : String) (rhs : i32) =
    let lhs =
        let! text = try_read_file lhs_path
        let! number = i32.try_parse text |> to_result "cannot parse $text"
        number

    lhs + rhs |> Result/Ok

Option конвертируется в Result с помощью метода to_result.