未验证 提交 70ad2e5f 编写于 作者: J Jan Dryk 提交者: GitHub

RFC FS-1123 Result module parity with Options (#13326)

上级 3e278bca
......@@ -22,3 +22,99 @@ module Result =
match result with
| Error e -> Error e
| Ok x -> binder x
[<CompiledName("IsOk")>]
let inline isOk result =
match result with
| Ok _ -> true
| Error _ -> false
[<CompiledName("IsError")>]
let inline isError result =
match result with
| Ok _ -> false
| Error _ -> true
[<CompiledName("DefaultValue")>]
let defaultValue value result =
match result with
| Error _ -> value
| Ok v -> v
[<CompiledName("DefaultWith")>]
let defaultWith defThunk result =
match result with
| Error _ -> defThunk ()
| Ok v -> v
[<CompiledName("Count")>]
let count result =
match result with
| Error _ -> 0
| Ok _ -> 1
[<CompiledName("Fold")>]
let fold<'T, 'Error, 'State> folder (state: 'State) (result: Result<'T, 'Error>) =
match result with
| Error _ -> state
| Ok x -> folder state x
[<CompiledName("FoldBack")>]
let foldBack<'T, 'Error, 'State> folder (result: Result<'T, 'Error>) (state: 'State) =
match result with
| Error _ -> state
| Ok x -> folder x state
[<CompiledName("Exists")>]
let exists predicate result =
match result with
| Error _ -> false
| Ok x -> predicate x
[<CompiledName("ForAll")>]
let forall predicate result =
match result with
| Error _ -> true
| Ok x -> predicate x
[<CompiledName("Contains")>]
let inline contains value result =
match result with
| Error _ -> false
| Ok v -> v = value
[<CompiledName("Iterate")>]
let iter action result =
match result with
| Error _ -> ()
| Ok x -> action x
[<CompiledName("ToArray")>]
let toArray result =
match result with
| Error _ -> [||]
| Ok x -> [| x |]
[<CompiledName("ToList")>]
let toList result =
match result with
| Error _ -> []
| Ok x -> [ x ]
[<CompiledName("ToSeq")>]
let toSeq result =
match result with
| Error _ -> []
| Ok x -> [ x ]
[<CompiledName("ToOption")>]
let toOption result =
match result with
| Error _ -> None
| Ok x -> Some x
[<CompiledName("ToValueOption")>]
let toValueOption result =
match result with
| Error _ -> ValueNone
| Ok x -> ValueSome x
......@@ -2,7 +2,7 @@
namespace Microsoft.FSharp.Core
open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators
open Microsoft.FSharp.Collections
/// <summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Core.FSharpResult`2"/>.</summary>
///
......@@ -68,3 +68,247 @@ module Result =
/// </example>
[<CompiledName("Bind")>]
val bind: binder: ('T -> Result<'U, 'TError>) -> result: Result<'T, 'TError> -> Result<'U, 'TError>
/// <summary>Returns true if the result is Ok.</summary>
/// <param name="result">The input result.</param>
///
/// <returns>True if the result is OK.</returns>
///
/// <example id="isOk-1">
/// <code lang="fsharp">
/// Ok 42 |> Result.isOk // evaluates to true
/// Error 42 |> Result.isOk // evaluates to false
/// </code>
/// </example>
[<CompiledName("IsOk")>]
val inline isOk: result: Result<'T, 'Error> -> bool
/// <summary>Returns true if the result is Error.</summary>
///
/// <param name="result">The input result.</param>
///
/// <returns>True if the result is Error.</returns>
///
/// <example id="isError-1">
/// <code lang="fsharp">
/// Ok 42 |> Result.isError // evaluates to false
/// Error 42 |> Result.isError // evaluates to true
/// </code>
/// </example>
[<CompiledName("IsError")>]
val inline isError: result: Result<'T, 'Error> -> bool
/// <summary>Gets the value of the result if the result is <c>Ok</c>, otherwise returns the specified default value.</summary>
///
/// <param name="value">The specified default value.</param>
/// <param name="result">The input result.</param>
///
/// <returns>The result if the result is Ok, else the default value.</returns>
///
/// <example id="defaultValue-1">
/// <code lang="fsharp">
/// Result.defaultValue 2 (Error 3) // evaluates to 2
/// Result.defaultValue 2 (Ok 1) // evaluates to 1
/// </code>
/// </example>
[<CompiledName("DefaultValue")>]
val defaultValue: value: 'T -> result: Result<'T, 'Error> -> 'T
/// <summary>Gets the value of the result if the result is <c>Ok</c>, otherwise evaluates <paramref name="defThunk"/> and returns the result.</summary>
///
/// <param name="defThunk">A thunk that provides a default value when evaluated.</param>
/// <param name="result">The input result.</param>
///
/// <returns>The result if the result is Ok, else the result of evaluating <paramref name="defThunk"/>.</returns>
/// <remarks><paramref name="defThunk"/> is not evaluated unless <paramref name="result"/> is <c>Error</c>.</remarks>
///
/// <example id="defaultWith-1">
/// <code lang="fsharp">
/// Ok 1 |> Result.defaultWith (fun () -> 99) // evaluates to 1
/// Error 2 |> Result.defaultWith (fun () -> 99) // evaluates to 99
/// </code>
/// </example>
[<CompiledName("DefaultWith")>]
val defaultWith: defThunk: (unit -> 'T) -> result: Result<'T, 'Error> -> 'T
/// <summary><c>count inp</c> evaluates to <c>match inp with Error _ -> 0 | Ok _ -> 1</c>.</summary>
///
/// <param name="result">The input result.</param>
///
/// <returns>A zero if the result is Error, a one otherwise.</returns>
///
/// <example id="count-1">
/// <code lang="fsharp">
/// Error 99 |> Result.count // evaluates to 0
/// Ok 99 |> Result.count // evaluates to 1
/// </code>
/// </example>
[<CompiledName("Count")>]
val count: result: Result<'T, 'Error> -> int
/// <summary><c>fold f s inp</c> evaluates to <c>match inp with Error _ -> s | Ok x -> f s x</c>.</summary>
///
/// <param name="folder">A function to update the state data when given a value from an result.</param>
/// <param name="state">The initial state.</param>
/// <param name="result">The input result.</param>
///
/// <returns>The original state if the result is Error, otherwise it returns the updated state with the folder
/// and the result value.</returns>
///
/// <example id="fold-1">
/// <code lang="fsharp">
/// (0, Error 2) ||> Result.fold (fun accum x -> accum + x * 2) // evaluates to 0
/// (0, Ok 1) ||> Result.fold (fun accum x -> accum + x * 2) // evaluates to 2
/// (10, Ok 1) ||> Result.fold (fun accum x -> accum + x * 2) // evaluates to 12
/// </code>
/// </example>
[<CompiledName("Fold")>]
val fold<'T, 'Error, 'State> :
folder: ('State -> 'T -> 'State) -> state: 'State -> result: Result<'T, 'Error> -> 'State
/// <summary><c>fold f inp s</c> evaluates to <c>match inp with Error _ -> s | Ok x -> f x s</c>.</summary>
///
/// <param name="folder">A function to update the state data when given a value from an result.</param>
/// <param name="result">The input result.</param>
/// <param name="state">The initial state.</param>
///
/// <returns>The original state if the result is Error, otherwise it returns the updated state with the folder
/// and the result value.</returns>
///
/// <example id="foldBack-1">
/// <code lang="fsharp">
/// (Error 2, 0) ||> Result.foldBack (fun x accum -> accum + x * 2) // evaluates to 0
/// (Ok 1, 0) ||> Result.foldBack (fun x accum -> accum + x * 2) // evaluates to 2
/// (Ok 1, 10) ||> Result.foldBack (fun x accum -> accum + x * 2) // evaluates to 12
/// </code>
/// </example>
[<CompiledName("FoldBack")>]
val foldBack<'T, 'Error, 'State> :
folder: ('T -> 'State -> 'State) -> result: Result<'T, 'Error> -> state: 'State -> 'State
/// <summary><c>exists p inp</c> evaluates to <c>match inp with Error _ -> false | Ok x -> p x</c>.</summary>
///
/// <param name="predicate">A function that evaluates to a boolean when given a value from the result type.</param>
/// <param name="result">The input result.</param>
///
/// <returns>False if the result is Error, otherwise it returns the result of applying the predicate
/// to the result value.</returns>
///
/// <example id="exists-1">
/// <code lang="fsharp">
/// Error 6 |> Result.exists (fun x -> x >= 5) // evaluates to false
/// Ok 42 |> Result.exists (fun x -> x >= 5) // evaluates to true
/// Ok 4 |> Result.exists (fun x -> x >= 5) // evaluates to false
/// </code>
/// </example>
[<CompiledName("Exists")>]
val exists: predicate: ('T -> bool) -> result: Result<'T, 'Error> -> bool
/// <summary><c>forall p inp</c> evaluates to <c>match inp with Error _ -> true | Ok x -> p x</c>.</summary>
///
/// <param name="predicate">A function that evaluates to a boolean when given a value from the result type.</param>
/// <param name="result">The input result.</param>
///
/// <returns>True if the result is Error, otherwise it returns the result of applying the predicate
/// to the result value.</returns>
///
/// <example id="forall-1">
/// <code lang="fsharp">
/// Error 1 |> Result.forall (fun x -> x >= 5) // evaluates to true
/// Ok 42 |> Result.forall (fun x -> x >= 5) // evaluates to true
/// Ok 4 |> Result.forall (fun x -> x >= 5) // evaluates to false
/// </code>
/// </example>
[<CompiledName("ForAll")>]
val forall: predicate: ('T -> bool) -> result: Result<'T, 'Error> -> bool
/// <summary>Evaluates to true if <paramref name="result"/> is <c>Ok</c> and its value is equal to <paramref name="value"/>.</summary>
///
/// <param name="value">The value to test for equality.</param>
/// <param name="result">The input result.</param>
///
/// <returns>True if the result is <c>Ok</c> and contains a value equal to <paramref name="value"/>, otherwise false.</returns>
///
/// <example id="contains-1">
/// <code lang="fsharp">
/// (99, Error 99) ||> Result.contains // evaluates to false
/// (99, Ok 99) ||> Result.contains // evaluates to true
/// (99, Ok 100) ||> Result.contains // evaluates to false
/// </code>
/// </example>
[<CompiledName("Contains")>]
val inline contains: value: 'T -> result: Result<'T, 'Error> -> bool when 'T: equality
/// <summary><c>iter f inp</c> executes <c>match inp with Error _ -> () | Ok x -> f x</c>.</summary>
///
/// <param name="action">A function to apply to the result value.</param>
/// <param name="result">The input result.</param>
///
/// <example id="iter-1">
/// <code lang="fsharp">
/// Error "Hello world" |> Result.iter (printfn "%s") // does nothing
/// Ok "Hello world" |> Result.iter (printfn "%s") // prints "Hello world"
/// </code>
/// </example>
[<CompiledName("Iterate")>]
val iter: action: ('T -> unit) -> result: Result<'T, 'Error> -> unit
/// <summary>Convert the result to an array of length 0 or 1.</summary>
///
/// <param name="result">The input result.</param>
///
/// <returns>The result array.</returns>
///
/// <example id="toArray-1">
/// <code lang="fsharp">
/// Error 42 |> Result.toArray // evaluates to [||]
/// Ok 42 |> Result.toArray // evaluates to [| 42 |]
/// </code>
/// </example>
[<CompiledName("ToArray")>]
val toArray: result: Result<'T, 'Error> -> 'T[]
/// <summary>Convert the result to a list of length 0 or 1.</summary>
///
/// <param name="result">The input result.</param>
///
/// <returns>The result list.</returns>
///
/// <example id="toList-1">
/// <code lang="fsharp">
/// Error 42 |> Result.toList // evaluates to []
/// Ok 42 |> Result.toList // evaluates to [ 42 ]
/// </code>
/// </example>
[<CompiledName("ToList")>]
val toList: result: Result<'T, 'Error> -> List<'T>
/// <summary>Convert the result to an Option value.</summary>
///
/// <param name="result">The input result.</param>
///
/// <returns>The option value.</returns>
///
/// <example id="toOption-1">
/// <code lang="fsharp">
/// Error 42 |> Result.toOption // evaluates to None
/// Ok 42 |> Result.toOption // evaluates to Some 42
/// </code>
/// </example>
[<CompiledName("ToOption")>]
val toOption: result: Result<'T, 'Error> -> Option<'T>
/// <summary>Convert the result to an Option value.</summary>
///
/// <param name="result">The input result.</param>
///
/// <returns>The result value.</returns>
///
/// <example id="toValueOption-1">
/// <code lang="fsharp">
/// Error 42 |> Result.toOption // evaluates to ValueNone
/// Ok 42 |> Result.toOption // evaluates to ValueSome 42
/// </code>
/// </example>
[<CompiledName("ToValueOption")>]
val toValueOption: result: Result<'T, 'Error> -> ValueOption<'T>
......@@ -117,6 +117,7 @@ type OptionModule() =
Assert.False( Option.contains None None)
Assert.True( Option.contains None (Some None))
[<Fact>]
member this.OfToNullable() =
Assert.True( Option.ofNullable (System.Nullable<int>()) = None)
......
......@@ -17,6 +17,8 @@ open Result
type ResultTests() =
let assertWasNotCalledThunk () = raise (exn "Thunk should not have been called.")
let fail_if_empty email=
if String.IsNullOrEmpty(email) then Error Empty else Ok email
......@@ -81,4 +83,93 @@ type ResultTests() =
|> bind addOneOk
|> shouldBeErrorWithValue "Error"
[<Fact>]
member this.IsOk() =
Assert.True(Result.isOk (Ok 1))
Assert.False(Result.isOk (Error 1))
[<Fact>]
member this.IsError() =
Assert.False(Result.isError (Ok 1))
Assert.True(Result.isError (Error 1))
[<Fact>]
member this.DefaultValue() =
Assert.AreEqual(Result.defaultValue 3 (Error 42), 3)
Assert.AreEqual(Result.defaultValue 3 (Ok 42), 42)
Assert.AreEqual(Result.defaultValue "1" (Error "x"), "1")
Assert.AreEqual(Result.defaultValue "1" (Ok "x"), "x")
[<Fact>]
member this.DefaultWith() =
Assert.AreEqual(Result.defaultWith (fun () -> 3) (Error 42), 3)
Assert.AreEqual(Result.defaultWith (fun () -> "1") (Error "42"), "1")
Assert.AreEqual(Result.defaultWith assertWasNotCalledThunk (Ok 42), 42)
Assert.AreEqual(Result.defaultWith assertWasNotCalledThunk (Ok "1"), "1")
[<Fact>]
member this.Count() =
Assert.AreEqual(Result.count (Ok 1), 1)
Assert.AreEqual(Result.count (Error 1), 0)
[<Fact>]
member this.Fold() =
Assert.AreEqual(Result.fold (fun accum x -> accum + x * 2) 0 (Error 2), 0)
Assert.AreEqual(Result.fold (fun accum x -> accum + x * 2) 0 (Ok 1), 2)
Assert.AreEqual(Result.fold (fun accum x -> accum + x * 2) 10 (Ok 1), 12)
[<Fact>]
member this.FoldBack() =
Assert.AreEqual(Result.foldBack (fun x accum -> accum + x * 2) (Error 2) 0, 0)
Assert.AreEqual(Result.foldBack (fun x accum -> accum + x * 2) (Ok 1) 0, 2)
Assert.AreEqual(Result.foldBack (fun x accum -> accum + x * 2) (Ok 1) 10, 12)
[<Fact>]
member this.Exists() =
Assert.AreEqual(Result.exists (fun x -> x >= 5) (Error 6), false)
Assert.AreEqual(Result.exists (fun x -> x >= 5) (Ok 42), true)
Assert.AreEqual(Result.exists (fun x -> x >= 5) (Ok 4), false)
[<Fact>]
member this.ForAll() =
Assert.AreEqual(Result.forall (fun x -> x >= 5) (Error 1), true)
Assert.AreEqual(Result.forall (fun x -> x >= 5) (Ok 42), true)
Assert.AreEqual(Result.forall (fun x -> x >= 5) (Ok 4), false)
[<Fact>]
member this.Contains() =
Assert.AreEqual(Result.contains 99 (Error 99), false)
Assert.AreEqual(Result.contains 99 (Ok 99), true)
Assert.AreEqual(Result.contains 99 (Ok 100), false)
[<Fact>]
member this.Iterate() =
let mutable i = 0
let increment _ =
i <- i + 1
Result.iter increment (Error "Hello world")
Assert.AreEqual(0, i)
Result.iter increment (Ok "Hello world")
Assert.AreEqual(1, i)
[<Fact>]
member this.ToArray() =
Assert.AreEqual(Result.toArray (Error 42), [| |])
Assert.AreEqual(Result.toArray (Ok 42), [| 42 |])
[<Fact>]
member this.ToList() =
Assert.AreEqual(Result.toList (Error 42), [ ])
Assert.AreEqual(Result.toList (Ok 42), [ 42 ])
[<Fact>]
member this.ToOption() =
Assert.AreEqual(Result.toOption (Error 42), None)
Assert.AreEqual(Result.toOption (Ok 42), Some 42)
[<Fact>]
member this.ToValueOption() =
Assert.AreEqual(Result.toValueOption (Error 42), ValueNone)
Assert.AreEqual(Result.toValueOption (Ok 42), ValueSome 42)
\ No newline at end of file
......@@ -1964,6 +1964,21 @@ Microsoft.FSharp.Core.RequiresExplicitTypeArgumentsAttribute: Void .ctor()
Microsoft.FSharp.Core.ResultModule: Microsoft.FSharp.Core.FSharpResult`2[T,TResult] MapError[TError,TResult,T](Microsoft.FSharp.Core.FSharpFunc`2[TError,TResult], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Microsoft.FSharp.Core.FSharpResult`2[TResult,TError] Bind[T,TResult,TError](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpResult`2[TResult,TError]], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Microsoft.FSharp.Core.FSharpResult`2[TResult,TError] Map[T,TResult,TError](Microsoft.FSharp.Core.FSharpFunc`2[T,TResult], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Boolean Contains[T,TError](T, Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Boolean Exists[T,TError](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Boolean ForAll[T,TError](Microsoft.FSharp.Core.FSharpFunc`2[T,System.Boolean], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Boolean IsError[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Boolean IsOk[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Int32 Count[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Microsoft.FSharp.Core.FSharpOption`1[T] ToOption[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Microsoft.FSharp.Core.FSharpValueOption`1[T] ToValueOption[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: T DefaultValue[T,TError](T, Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: T DefaultWith[T,TError](Microsoft.FSharp.Core.FSharpFunc`2[Microsoft.FSharp.Core.Unit,T], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: TState FoldBack[T,TError,TState](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpFunc`2[TState,TState]], Microsoft.FSharp.Core.FSharpResult`2[T,TError], TState)
Microsoft.FSharp.Core.ResultModule: TState Fold[T,TError,TState](Microsoft.FSharp.Core.FSharpFunc`2[TState,Microsoft.FSharp.Core.FSharpFunc`2[T,TState]], TState, Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: T[] ToArray[T,TError](Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.ResultModule: Void Iterate[T,TError](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.Unit], Microsoft.FSharp.Core.FSharpResult`2[T,TError])
Microsoft.FSharp.Core.SealedAttribute: Boolean Value
Microsoft.FSharp.Core.SealedAttribute: Boolean get_Value()
Microsoft.FSharp.Core.SealedAttribute: Void .ctor()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册