What do you mean by 'take a type'? Are you passing a System.Type object at runtime? Or do you mean e.g.

1
let f<'a,'b>(g : 'a -> 'b ) : Async<'a> = ...

or what? What is the pseudocode of the implementation?

By on 12/3/2010 2:50 PM ()
1
2
3
let create = function
  | SyncFunc(f) -> (fun r -> async { return f(r) })
  | AsyncFunc(f) -> f

My thought is that I create Active Patterns to identify the type of function, but a discriminated union could work, as well. I would just prefer to not have to define the function as a SyncFunc(fun r -> ...) or AsyncFunc(fun r -> async { ... }) and just pass the raw function.

In my use, the types are almost exactly the same except for the Async computation. So consider the discriminated union to be like:

1
2
3
type Fun
  | SyncFunc of 'a -> 'b
  | AsyncFunc of 'a -> Async<'b>

Ryan

By on 12/3/2010 4:48 PM ()

I see, yes, DUs seem like the best (only?) fit here.

By on 12/3/2010 5:13 PM ()
1
2
3
4
5
6
7
8
9
10
11
12
open Microsoft.FSharp.Reflection

let (|SyncF|AsyncF|) f =
	let domain, range = FSharpType.GetFunctionElements(f.GetType())

	if range = typeof<Async<_>>
	then AsyncF(f)
	else SyncF(f)

	let createInvoker = function
	| SyncF(f) -> (fun r -> async { return f r })
	| AsyncF(f) -> f

I've gotten this far, but the compiler thinks that the f in the latter part of the pattern match is an 'a -> 'b instead of a 'a -> Async<'b>. :(

Ryan

By on 12/3/2010 5:59 PM ()
1
2
3
4
5
6
7
8
  open Microsoft.FSharp.Reflection

  let (|SyncF|AsyncF|) f =
    let domain, range = FSharpType.GetFunctionElements(f.GetType())

    if range = typeof<Async<_>>
      then AsyncF(f)
      else SyncF(fun r -> async { return f r })

I tried this one, too, but I get the same problem.

Ryan

By on 12/3/2010 6:01 PM ()

In order to get something like what you are asking for you need to really mess with the type system and will need to add some type annotations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let f1 = (fun x -> x + 1)
let f2 = (fun x -> async { return x + 1 })
 
let syncOfAsync (f':'a->'c) : Choice<'a->'b,'a->Async<'b>> =
    match box f' with
    | :? ('a -> 'b) as f -> Choice1Of2 f
    | :? ('a -> Async<'b>) as f -> Choice2Of2 f
 
let (|SyncF|AsyncF|) ((f':'a->'c),(dummy:'b)) = syncOfAsync<'a,'c,'b> f'
    
let f3 : int -> int =
    match f2,Unchecked.defaultof<_> with
    | SyncF f -> f
    | AsyncF f -> (fun x -> x |> f |> Async.RunSynchronously)
f3 2

This works because we allow 'c to vary independently with 'b but in order to return the correct type we are want we are forced to pass a dummy value of the 'b type into the active pattern.
Also you could use a match against type to convert the function type to the one your looking for:
For example if you have int -> string or int -> Async<string> functions running around and want to convert them all to int -> string then do the following:

1
2
3
4
5
6
7
8
9
10
11
let syncOrAsyncFToSyncF (f':'a->'c) : 'a -> 'b =
    match box f' with
    | :? ('a -> 'b) as f -> f
    | :? ('a -> Async<'b>) as f -> (fun x -> x |> f |> Async.RunSynchronously)
let syncOrAsyncFToAsyncF (f':'a->'c) : 'a -> Async<'b> =
    match box f' with
    | :? ('a -> 'b) as f -> (fun x -> async { return f x })
    | :? ('a -> Async<'b>) as f -> f
let f4 : int -> string = syncOrAsyncFToSyncF (fun x -> x.ToString())
// or
let f5 : int -> string = syncOrAsyncFToSyncF (fun x -> async { return "bob" })


Hope this helps.

By on 12/8/2010 11:35 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper