diff --git a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs index 0a93e79fca49..15171991db22 100644 --- a/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs +++ b/src/fsharp/FSharp.Core.Unittests/FSharp.Core/Microsoft.FSharp.Core/OptionModule.fs @@ -27,6 +27,66 @@ type OptionModule() = Assert.AreEqual( Option.flatten (Some <| Some 1), Some 1) Assert.AreEqual( Option.flatten (Some <| Some ""), Some "") + [] + member this.Apply () = + let oneMinus x = 1 - x + Assert.AreEqual(Option.apply None None, None) + Assert.AreEqual(Option.apply (Some 2) None, None) + Assert.AreEqual(Option.apply None (Some oneMinus), None) + Assert.AreEqual(Option.apply (Some 2) (Some oneMinus), Some -1) + + let afterX x = "x" + x + Assert.AreEqual(Option.apply None None, None) + Assert.AreEqual(Option.apply (Some "y") None, None) + Assert.AreEqual(Option.apply None (Some afterX), None) + Assert.AreEqual(Option.apply (Some "y") (Some afterX), Some "xy") + + let lengthPlus3 x = 3 + String.length x + Assert.AreEqual(Option.apply None (Some lengthPlus3), None) + Assert.AreEqual(Option.apply (Some "y") (Some lengthPlus3), Some 4) + + [] + member this.MapPipeApply () = + let add3 x y z = string x + string y + string z + Assert.AreEqual(Option.map add3 None |> Option.apply None |> Option.apply None, None) + Assert.AreEqual(Option.map add3 None |> Option.apply (Some 2) |> Option.apply None, None) + Assert.AreEqual(Option.map add3 (Some 1) |> Option.apply None |> Option.apply None, None) + Assert.AreEqual(Option.map add3 (Some 1) |> Option.apply (Some 2) |> Option.apply None, None) + Assert.AreEqual(Option.map add3 None |> Option.apply None |> Option.apply (Some 3), None) + Assert.AreEqual(Option.map add3 None |> Option.apply (Some 2) |> Option.apply (Some 3), None) + Assert.AreEqual(Option.map add3 (Some 1) |> Option.apply None |> Option.apply (Some 3), None) + Assert.AreEqual(Option.map add3 (Some 1) |> Option.apply (Some 2) |> Option.apply (Some 3), Some "123") + + let concat3 x y z = x + y + z + Assert.AreEqual(Option.map concat3 None |> Option.apply None |> Option.apply None, None) + Assert.AreEqual(Option.map concat3 None |> Option.apply (Some "y") |> Option.apply None, None) + Assert.AreEqual(Option.map concat3 (Some "x") |> Option.apply None |> Option.apply None, None) + Assert.AreEqual(Option.map concat3 (Some "x") |> Option.apply (Some "y") |> Option.apply None, None) + Assert.AreEqual(Option.map concat3 None |> Option.apply None |> Option.apply (Some "z"), None) + Assert.AreEqual(Option.map concat3 None |> Option.apply (Some "y") |> Option.apply (Some "z"), None) + Assert.AreEqual(Option.map concat3 (Some "x") |> Option.apply None |> Option.apply (Some "z"), None) + Assert.AreEqual(Option.map concat3 (Some "x") |> Option.apply (Some "y") |> Option.apply (Some "z"), Some "xyz") + + let mix3 x y z = String.length x * y + int32 z + Assert.AreEqual(Option.map mix3 None |> Option.apply None |> Option.apply None, None) + Assert.AreEqual(Option.map mix3 None |> Option.apply (Some 6) |> Option.apply None, None) + Assert.AreEqual(Option.map mix3 (Some "asdwxf") |> Option.apply None |> Option.apply None, None) + Assert.AreEqual(Option.map mix3 (Some "asdwxf") |> Option.apply (Some 6) |> Option.apply None, None) + Assert.AreEqual(Option.map mix3 None |> Option.apply None |> Option.apply (Some 6UL), None) + Assert.AreEqual(Option.map mix3 None |> Option.apply (Some 6) |> Option.apply (Some 6UL), None) + Assert.AreEqual(Option.map mix3 (Some "asdwxf") |> Option.apply None |> Option.apply (Some 6UL), None) + Assert.AreEqual(Option.map mix3 (Some "asdwxf") |> Option.apply (Some 6) |> Option.apply (Some 6UL), Some 42) + + [] + member this.MapBindApplyEquivalenceProperties () = + let fn x = x + 3 + Assert.AreEqual(Option.map fn None, Option.bind (fn >> Some) None) + Assert.AreEqual(Option.map fn (Some 5), Option.bind (fn >> Some) (Some 5)) + Assert.AreEqual(Option.apply None None, (fun xOpt -> Option.bind (fun f -> Option.map f xOpt)) None None) + Assert.AreEqual(Option.apply (Some 5) None, (fun xOpt -> Option.bind (fun f -> Option.map f xOpt)) (Some 5) None) + Assert.AreEqual(Option.apply None (Some fn), (fun xOpt -> Option.bind (fun f -> Option.map f xOpt)) None (Some fn)) + Assert.AreEqual(Option.apply (Some 5) (Some fn), (fun xOpt -> Option.bind (fun f -> Option.map f xOpt)) (Some 5) (Some fn)) + [] member this.FilterSomeIntegerWhenPredicateReturnsTrue () = let test x = diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs index 8e16d4a1b511..3136c81f0b21 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.coreclr.fs @@ -2722,6 +2722,7 @@ Microsoft.FSharp.Core.OptionModule: Boolean IsSome[T](Microsoft.FSharp.Core.FSha Microsoft.FSharp.Core.OptionModule: Int32 Count[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Int32 GetHashCode() Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T](Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Apply[T,TResult](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map2[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map3[T1,T2,T3,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.FSharpFunc`2[T3,TResult]]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2], Microsoft.FSharp.Core.FSharpOption`1[T3]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs index 4d42c7b1e66d..de590a3e1e5b 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.net40.fs @@ -2756,6 +2756,7 @@ Microsoft.FSharp.Core.OptionModule: Boolean IsSome[T](Microsoft.FSharp.Core.FSha Microsoft.FSharp.Core.OptionModule: Int32 Count[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Int32 GetHashCode() Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T](Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Apply[T,TResult](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map2[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map3[T1,T2,T3,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.FSharpFunc`2[T3,TResult]]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2], Microsoft.FSharp.Core.FSharpOption`1[T3]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs index 31deb1022e49..648074ec87c6 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable259.fs @@ -2727,6 +2727,7 @@ Microsoft.FSharp.Core.OptionModule: Boolean IsSome[T](Microsoft.FSharp.Core.FSha Microsoft.FSharp.Core.OptionModule: Int32 Count[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Int32 GetHashCode() Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T](Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Apply[T,TResult](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map2[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map3[T1,T2,T3,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.FSharpFunc`2[T3,TResult]]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2], Microsoft.FSharp.Core.FSharpOption`1[T3]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs index 8bfc4fd248fc..aae36504c261 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable47.fs @@ -2728,6 +2728,7 @@ Microsoft.FSharp.Core.OptionModule: Boolean IsSome[T](Microsoft.FSharp.Core.FSha Microsoft.FSharp.Core.OptionModule: Int32 Count[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Int32 GetHashCode() Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T](Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Apply[T,TResult](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map2[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map3[T1,T2,T3,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.FSharpFunc`2[T3,TResult]]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2], Microsoft.FSharp.Core.FSharpOption`1[T3]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs index 27d06441089a..27623f8e32e6 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable7.fs @@ -2740,6 +2740,7 @@ Microsoft.FSharp.Core.OptionModule: Boolean IsSome[T](Microsoft.FSharp.Core.FSha Microsoft.FSharp.Core.OptionModule: Int32 Count[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Int32 GetHashCode() Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T](Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Apply[T,TResult](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map2[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map3[T1,T2,T3,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.FSharpFunc`2[T3,TResult]]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2], Microsoft.FSharp.Core.FSharpOption`1[T3]) diff --git a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs index 01043abde07e..f959754d74cd 100644 --- a/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs +++ b/src/fsharp/FSharp.Core.Unittests/SurfaceArea.portable78.fs @@ -2727,6 +2727,7 @@ Microsoft.FSharp.Core.OptionModule: Boolean IsSome[T](Microsoft.FSharp.Core.FSha Microsoft.FSharp.Core.OptionModule: Int32 Count[T](Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Int32 GetHashCode() Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Collections.FSharpList`1[T] ToList[T](Microsoft.FSharp.Core.FSharpOption`1[T]) +Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Apply[T,TResult](Microsoft.FSharp.Core.FSharpOption`1[T], Microsoft.FSharp.Core.FSharpOption`1[Microsoft.FSharp.Core.FSharpFunc`2[T,TResult]]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Bind[T,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T,Microsoft.FSharp.Core.FSharpOption`1[TResult]], Microsoft.FSharp.Core.FSharpOption`1[T]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map2[T1,T2,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,TResult]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2]) Microsoft.FSharp.Core.OptionModule: Microsoft.FSharp.Core.FSharpOption`1[TResult] Map3[T1,T2,T3,TResult](Microsoft.FSharp.Core.FSharpFunc`2[T1,Microsoft.FSharp.Core.FSharpFunc`2[T2,Microsoft.FSharp.Core.FSharpFunc`2[T3,TResult]]], Microsoft.FSharp.Core.FSharpOption`1[T1], Microsoft.FSharp.Core.FSharpOption`1[T2], Microsoft.FSharp.Core.FSharpOption`1[T3]) diff --git a/src/fsharp/FSharp.Core/option.fs b/src/fsharp/FSharp.Core/option.fs index 608c2966edec..811b0e4e9141 100644 --- a/src/fsharp/FSharp.Core/option.fs +++ b/src/fsharp/FSharp.Core/option.fs @@ -64,6 +64,12 @@ namespace Microsoft.FSharp.Core | Some x, Some y, Some z -> Some <| f x y z | _ -> None + [] + let apply inp fOpt = + match fOpt, inp with + | Some f, Some x -> Some (f x) + | _ -> None + [] let bind f inp = match inp with None -> None | Some x -> f x diff --git a/src/fsharp/FSharp.Core/option.fsi b/src/fsharp/FSharp.Core/option.fsi index 7a78ca1d889a..92c4ece7bf70 100644 --- a/src/fsharp/FSharp.Core/option.fsi +++ b/src/fsharp/FSharp.Core/option.fsi @@ -140,6 +140,13 @@ namespace Microsoft.FSharp.Core [] val map3: mapping:('T1 -> 'T2 -> 'T3 -> 'U) -> 'T1 option -> 'T2 option -> 'T3 option -> 'U option + /// apply inp fOpt evaluates to match inp, fOpt with Some x, f -> Some (f x) | _ -> None. + /// The input option. + /// An optional function to apply to the option value. + /// An option of the input value after applying the mapping function, or None if either the input or the mapping function is None. + [] + val apply: option:'T option -> mappingOpt:('T -> 'U) option -> 'U option + /// bind f inp evaluates to match inp with None -> None | Some x -> f x /// A function that takes the value of type T from an option and transforms it into /// an option containing a value of type U.