Skip to content

Commit

Permalink
[FS-1045] Add FuncConvert.FromFunc, FuncConvert.FromAction APIs (#4815)
Browse files Browse the repository at this point in the history
* add func overloads

* adjust based on C# testing

* fix test break

* fix test

* update surface area

* fix test

* align inlines

* Merge error
  • Loading branch information
dsyme authored and KevinRansom committed May 25, 2018
1 parent fce9e68 commit 6a73326
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 44 deletions.
4 changes: 0 additions & 4 deletions src/fsharp/FSharp.Core/Linq.fs
Original file line number Diff line number Diff line change
Expand Up @@ -782,11 +782,7 @@ module LeafExpressionConverter =
typedefof<Action<_>>, tyargs
else
let tyargs = [| vP.Type; bodyP.Type |]
#if FX_NO_CONVERTER
typedefof<Func<_, _>>, tyargs
#else
typedefof<System.Converter<_, _>>, tyargs
#endif
let convType = lambdaTy.MakeGenericType tyargs
let convDelegate = Expression.Lambda(convType, bodyP, [| vP |]) |> asExpr
Expression.Call(typeof<FuncConvert>,"ToFSharpFunc", tyargs,[| convDelegate |]) |> asExpr
Expand Down
85 changes: 63 additions & 22 deletions src/fsharp/FSharp.Core/prim-types.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2884,40 +2884,82 @@ namespace Microsoft.FSharp.Core


type FSharpFunc<'T,'Res> with
#if FX_NO_CONVERTER

// Note: this is not made public in the signature, because of conflicts with the Converter overload.
// The method remains in case someone is calling it via reflection.
[<CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")>]
static member op_Implicit (func : System.Func<_,_>) : ('T -> 'Res) = (fun t -> func.Invoke(t))
static member op_Implicit(converter : System.Func<_,_>) : ('T -> 'Res) = (fun t -> converter.Invoke(t))

// Note: this is not made public in the signature, because of conflicts with the Converter overload.
// The method remains in case someone is calling it via reflection.
[<CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")>]
static member op_Implicit (func : ('T -> 'Res) ) = new System.Func<'T,'Res>(func)
#else
static member op_Implicit(func : ('T -> 'Res) ) = new System.Func<'T,'Res>(func)

#if !FX_NO_CONVERTER
[<CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")>]
static member op_Implicit (converter : System.Converter<_,_>) : ('T -> 'Res) = (fun t -> converter.Invoke(t))
static member op_Implicit(f : System.Converter<_,_>) : ('T -> 'Res) = (fun t -> f.Invoke(t))

[<CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates")>]
static member op_Implicit (func : ('T -> 'Res) ) = new System.Converter<'T,'Res>(func)

static member FromConverter (converter : System.Converter<_,_>) : ('T -> 'Res) = (fun t -> converter.Invoke(t))
static member ToConverter ( func : ('T -> 'Res) ) = new System.Converter<'T,'Res>(func)
static member FromConverter (converter: System.Converter<_,_>) : ('T -> 'Res) = (fun t -> converter.Invoke(t))

static member ToConverter (func: ('T -> 'Res) ) = new System.Converter<'T,'Res>(func)
#endif
static member InvokeFast (func:FSharpFunc<_,_>, arg1:'T, arg2:'Res) = OptimizedClosures.invokeFast2(func, arg1, arg2)
static member InvokeFast (func:FSharpFunc<_,_>, arg1:'T, arg2:'Res, arg3) = OptimizedClosures.invokeFast3(func, arg1, arg2, arg3)
static member InvokeFast (func:FSharpFunc<_,_>, arg1:'T, arg2:'Res, arg3, arg4) = OptimizedClosures.invokeFast4(func, arg1, arg2, arg3, arg4)
static member InvokeFast (func:FSharpFunc<_,_>, arg1:'T, arg2:'Res, arg3, arg4, arg5) = OptimizedClosures.invokeFast5(func, arg1, arg2, arg3, arg4, arg5)

static member InvokeFast (func:FSharpFunc<_,_>, arg1: 'T, arg2: 'Res) = OptimizedClosures.invokeFast2(func, arg1, arg2)

static member InvokeFast (func:FSharpFunc<_,_>, arg1: 'T, arg2: 'Res, arg3) = OptimizedClosures.invokeFast3(func, arg1, arg2, arg3)

static member InvokeFast (func:FSharpFunc<_,_>, arg1: 'T, arg2: 'Res, arg3, arg4) = OptimizedClosures.invokeFast4(func, arg1, arg2, arg3, arg4)

static member InvokeFast (func:FSharpFunc<_,_>, arg1: 'T, arg2: 'Res, arg3, arg4, arg5) = OptimizedClosures.invokeFast5(func, arg1, arg2, arg3, arg4, arg5)

[<AbstractClass>]
[<Sealed>]
type FuncConvert =
static member ToFSharpFunc (action: Action<_>) = (fun t -> action.Invoke(t))
#if FX_NO_CONVERTER
static member ToFSharpFunc (converter: System.Func<_, _>) = (fun t -> converter.Invoke(t))
#else
static member ToFSharpFunc (converter: Converter<_,_>) = (fun t -> converter.Invoke(t))
#endif
static member FuncFromTupled (func:'T1 * 'T2 -> 'Res) = (fun a b -> func (a, b))
static member FuncFromTupled (func:'T1 * 'T2 * 'T3 -> 'Res) = (fun a b c -> func (a, b, c))
static member FuncFromTupled (func:'T1 * 'T2 * 'T3 * 'T4 -> 'Res) = (fun a b c d -> func (a, b, c, d))
static member FuncFromTupled (func:'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'Res) = (fun a b c d e-> func (a, b, c, d, e))

static member inline ToFSharpFunc (action: Action<_>) = (fun t -> action.Invoke(t))

#if !FX_NO_CONVERTER
static member inline ToFSharpFunc (converter : Converter<_,_>) = (fun t -> converter.Invoke(t))
#endif

// Note: this is not made public in the signature, because of conflicts with the Converter overload.
// The method remains in case someone is calling it via reflection.
static member inline ToFSharpFunc (converter: System.Func<_, _>) = (fun t -> converter.Invoke(t))

static member inline FromFunc (func: System.Func<_>) = (fun () -> func.Invoke())

static member inline FromFunc (func: System.Func<_, _>) = (fun t -> func.Invoke(t))

static member inline FromFunc (func: System.Func<_, _, _>) = (fun t1 t2 -> func.Invoke(t1,t2))

static member inline FromFunc (func: System.Func<_, _, _, _>) = (fun t1 t2 t3 -> func.Invoke(t1,t2,t3))

static member inline FromFunc (func: System.Func<_, _, _, _, _>) = (fun t1 t2 t3 t4 -> func.Invoke(t1,t2,t3,t4))

static member inline FromFunc (func: System.Func<_, _, _, _, _, _>) = (fun t1 t2 t3 t4 t5 -> func.Invoke(t1,t2,t3,t4,t5))

static member inline FromAction (action: System.Action) = (fun () -> action.Invoke())

static member inline FromAction (action: System.Action<_>) = (fun t -> action.Invoke(t))

static member inline FromAction (action: System.Action<_, _>) = (fun t1 t2 -> action.Invoke(t1,t2))

static member inline FromAction (action: System.Action<_, _, _>) = (fun t1 t2 t3 -> action.Invoke(t1,t2,t3))

static member inline FromAction (action: System.Action<_, _, _, _>) = (fun t1 t2 t3 t4 -> action.Invoke(t1,t2,t3,t4))

static member inline FromAction (action: System.Action<_, _, _, _, _>) = (fun t1 t2 t3 t4 t5 -> action.Invoke(t1,t2,t3,t4,t5))

static member inline FuncFromTupled (func: 'T1 * 'T2 -> 'Res) = (fun a b -> func (a, b))

static member inline FuncFromTupled (func: 'T1 * 'T2 * 'T3 -> 'Res) = (fun a b c -> func (a, b, c))

static member inline FuncFromTupled (func: 'T1 * 'T2 * 'T3 * 'T4 -> 'Res) = (fun a b c d -> func (a, b, c, d))

static member inline FuncFromTupled (func: 'T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'Res) = (fun a b c d e -> func (a, b, c, d, e))

//-------------------------------------------------------------------------
// Refs
Expand Down Expand Up @@ -5433,7 +5475,6 @@ namespace Microsoft.FSharp.Core
let TanhDynamic x = TanhDynamicImplTable<_>.Result x
let PowDynamic x y = PowDynamicImplTable<_,_>.Result x y


open OperatorIntrinsics

let inline (..) (start:^T) (finish:^T) =
Expand Down
87 changes: 76 additions & 11 deletions src/fsharp/FSharp.Core/prim-types.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -1445,16 +1445,17 @@ namespace Microsoft.FSharp.Core
[<AbstractClass>]
type FSharpFunc<'T,'U> =

/// <summary>Construct an instance of an F# first class function value </summary>
/// <returns>The created F# function.</returns>
/// <summary>Construct an instance of an F# first class function value </summary>
/// <returns>The created F# function.</returns>
new : unit -> FSharpFunc<'T,'U>

/// <summary>Invoke an F# first class function value with one argument</summary>
/// <param name="func"></param>
/// <returns>'U</returns>
abstract member Invoke : func:'T -> 'U

#if !FX_NO_CONVERTER

/// <summary>Convert an F# first class function value to a value of type <c>System.Converter</c></summary>
/// <param name="func">The input function.</param>
/// <returns>A System.Converter of the function type.</returns>
Expand All @@ -1469,6 +1470,7 @@ namespace Microsoft.FSharp.Core
/// <param name="func">The input function.</param>
/// <returns>System.Converter&lt;'T,'U&gt;</returns>
static member ToConverter : func:('T -> 'U) -> System.Converter<'T,'U>

/// <summary>Convert an value of type <c>System.Converter</c> to a F# first class function value </summary>
/// <param name="converter">The input System.Converter.</param>
/// <returns>An F# function of the same type.</returns>
Expand Down Expand Up @@ -1520,36 +1522,96 @@ namespace Microsoft.FSharp.Core
type FuncConvert =

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="action">The input action.</param>
/// <param name="action">The input Action delegate.</param>
/// <returns>The F# function.</returns>
static member ToFSharpFunc : action:Action<'T> -> ('T -> unit)
static member inline ToFSharpFunc : action:Action<'T> -> ('T -> unit)

#if !FX_NO_CONVERTER
/// <summary>Convert the given Converter delegate object to an F# function value</summary>
/// <param name="converter">The input Converter.</param>
/// <param name="converter">The input Converter delegate.</param>
/// <returns>The F# function.</returns>
static member ToFSharpFunc : converter:Converter<'T,'U> -> ('T -> 'U)
static member inline ToFSharpFunc : converter:Converter<'T,'U> -> ('T -> 'U)
#endif

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="func">The input Action delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromAction : action:Action -> (unit -> unit)

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="func">The input Action delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromAction : action:Action<'T> -> ('T -> unit)

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="func">The input Action delegate.</param>
/// <returns>The F#funcfunction.</returns>
static member inline FromAction : action:Action<'T1,'T2> -> ('T1 -> 'T2 -> unit)

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="func">The input Action delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromAction : action:Action<'T1,'T2,'T3> -> ('T1 -> 'T2 -> 'T3 -> unit)

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="func">The input Action delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromAction : action:Action<'T1,'T2,'T3,'T4> -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> unit)

/// <summary>Convert the given Action delegate object to an F# function value</summary>
/// <param name="func">The input Action delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromAction : action:Action<'T1,'T2,'T3,'T4,'T5> -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'T5 -> unit)

/// <summary>Convert the given Func delegate object to an F# function value</summary>
/// <param name="func">The input Func delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromFunc : func:Func<'T> -> (unit -> 'T)

/// <summary>Convert the given Func delegate object to an F# function value</summary>
/// <param name="func">The input Func delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromFunc : func:Func<'T,'U> -> ('T -> 'U)

/// <summary>Convert the given Func delegate object to an F# function value</summary>
/// <param name="func">The input Func delegate.</param>
/// <returns>The F#funcfunction.</returns>
static member inline FromFunc : func:Func<'T1,'T2,'U> -> ('T1 -> 'T2 -> 'U)

/// <summary>Convert the given Func delegate object to an F# function value</summary>
/// <param name="func">The input Func delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromFunc : func:Func<'T1,'T2,'T3,'U> -> ('T1 -> 'T2 -> 'T3 -> 'U)

/// <summary>Convert the given Func delegate object to an F# function value</summary>
/// <param name="func">The input Func delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromFunc : func:Func<'T1,'T2,'T3,'T4,'U> -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'U)

/// <summary>Convert the given Func delegate object to an F# function value</summary>
/// <param name="func">The input Func delegate.</param>
/// <returns>The F# function.</returns>
static member inline FromFunc : func:Func<'T1,'T2,'T3,'T4,'T5,'U> -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'T5 -> 'U)

/// <summary>A utility function to convert function values from tupled to curried form</summary>
/// <param name="func">The input tupled function.</param>
/// <returns>The output curried function.</returns>
static member FuncFromTupled : func:('T1 * 'T2 -> 'U) -> ('T1 -> 'T2 -> 'U)
static member inline FuncFromTupled : func:('T1 * 'T2 -> 'U) -> ('T1 -> 'T2 -> 'U)

/// <summary>A utility function to convert function values from tupled to curried form</summary>
/// <param name="func">The input tupled function.</param>
/// <returns>The output curried function.</returns>
static member FuncFromTupled : func:('T1 * 'T2 * 'T3 -> 'U) -> ('T1 -> 'T2 -> 'T3 -> 'U)
static member inline FuncFromTupled : func:('T1 * 'T2 * 'T3 -> 'U) -> ('T1 -> 'T2 -> 'T3 -> 'U)

/// <summary>A utility function to convert function values from tupled to curried form</summary>
/// <param name="func">The input tupled function.</param>
/// <returns>The output curried function.</returns>
static member FuncFromTupled : func:('T1 * 'T2 * 'T3 * 'T4 -> 'U) -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'U)
static member inline FuncFromTupled : func:('T1 * 'T2 * 'T3 * 'T4 -> 'U) -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'U)

/// <summary>A utility function to convert function values from tupled to curried form</summary>
/// <param name="func">The input tupled function.</param>
/// <returns>The output curried function.</returns>
static member FuncFromTupled : func:('T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'U) -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'T5 -> 'U)
static member inline FuncFromTupled : func:('T1 * 'T2 * 'T3 * 'T4 * 'T5 -> 'U) -> ('T1 -> 'T2 -> 'T3 -> 'T4 -> 'T5 -> 'U)

/// <summary>An implementation module used to hold some private implementations of function
/// value invocation.</summary>
Expand Down Expand Up @@ -1584,6 +1646,7 @@ namespace Microsoft.FSharp.Core
/// typically used directly from either F# code or from other CLI languages.</summary>
[<AbstractClass>]
type FSharpFunc<'T1,'T2,'T3,'U> =

inherit FSharpFunc<'T1,('T2 -> 'T3 -> 'U)>

/// <summary>Invoke an F# first class function value that accepts three curried arguments
Expand Down Expand Up @@ -1626,6 +1689,7 @@ namespace Microsoft.FSharp.Core
/// <param name="func">The input function.</param>
/// <returns>The optimized function.</returns>
static member Adapt : func:('T1 -> 'T2 -> 'T3 -> 'T4 -> 'U) -> FSharpFunc<'T1,'T2,'T3,'T4,'U>

/// <summary>Construct an optimized function value that can accept four curried
/// arguments without intervening execution.</summary>
/// <returns>The optimized function.</returns>
Expand Down Expand Up @@ -3204,6 +3268,7 @@ namespace Microsoft.FSharp.Control
module LazyExtensions =

type System.Lazy<'T> with

/// <summary>Creates a lazy computation that evaluates to the result of the given function when forced.</summary>
/// <param name="creator">The function to provide the value when needed.</param>
/// <returns>The created Lazy object.</returns>
Expand Down
Loading

0 comments on commit 6a73326

Please sign in to comment.