After working through this a bit more, I think I started off down the wrong path. I pulled back a bit and am trying to now map to the Create and CreateWithDisposable methods. What I want to do is allow an F# function to be passed in and converted to the appropriate c# delegate type. The CreateWithDisposable is easy. However, the Create is more difficult, and I'm not sure it's even possible. Here's what I have:

1
2
3
4
5
let create (f: IObservable<'a> -> unit -> unit) =

  let subscriber = new Func<_,_>(f)

  Observable.Create(subscriber)

What I want to do is convert the unit -> unit to an Action. The problem is that the Action is the return type. Yes, I can just use Action and convert my function to be an action, but I would love to hide that. Is it possible?

By on 12/18/2009 3:16 PM ()

I don't know what the signature of Observable.Create is, but if I have guessed right below, then the code below shows how:

1
2
3
4
5
6
7
8
9
10
 

open System
module Observable =
    let Create(f:Func<IObservable<'a>,Action>) : IObservable<'a> = null
let create (f: IObservable<'a> -> unit -> unit) =
    let subscriber = new Func<IObservable<'a>,Action>(fun a -> new Action(f a))
    Observable.Create(subscriber)

(click 'quote' on my reply to see how to format code)

By on 12/18/2009 3:33 PM ()

I don't know what the signature of Observable.Create is, but if I have guessed right below, then the code below shows how:

1
2
3
4
5
6
7
 
open System
module Observable =
    let Create(f:Func<IObservable<'a>,Action>) : IObservable<'a> = null
let create (f: IObservable<'a> -> unit -> unit) =
    let subscriber = new Func<IObservable<'a>,Action>(fun a -> new Action(f a))
    Observable.Create(subscriber)

(click 'quote' on my reply to see how to format code)

That is exactly what I was looking for. Thanks, Brian! I was able to get it down to this:

1
2
3
4
let asAction f = Action(f)
let create f =
    let subscriber = Func<_,_>(f asAction)
    Observable.Create(subscriber)

I love F# and its beautiful terseness! I'm curious, though, whether it is considered better to include the `new` or leave it off since it is not required? Does it matter?

By on 12/30/2009 1:25 PM ()

You can get the original code to work just fine if you replace the match f with with match box f with. This allows the generic type checking pattern to then work. Also use as construct as well.

1
2
3
4
5
6
7
8
9
10
11
let magic (func:_ -> _) arg =
    match box func with
    | :? (int -> string) as f -> f arg
    | :? (int -> int) as f -> (f arg).ToString()
    | _ -> "<none>"

let create (f: IObservable -> 'b) =
    match box f with
    | :? (IObservable -> Action) as f -> Observable.Create(f)
    | :? (IObservable -> IDisposable) as f -> Observable.CreateWithDisposable(f)
    | _ -> failwith "Opps!"

*Note* that the issue you might have been having before is that f needed to be remapped by the pattern matching engine using the as keyword otherwise the type inference engine is attempting to match f against both Create(...) and CreateWithDisposable(...). I also assume that the types of Create(...) and CreateWithDisposable(...) take functions arguments correct?

By on 12/14/2009 5:25 PM ()

I think it would be better to use overloading. E.g.

1
2
3
4
5
6
type ObservableCreator =
  static member Create(f: #IObservable -> Action) =
    Observable.Create(f)
  
  static member Create(f: #IObservable -> #IDisposable) =
    Observable.CreateWithDisposable(f)
By on 12/13/2009 1:55 AM ()

Well, I really wanted to know if it were possible to do pattern matching on function types, and if so, to be able to change that out. In other words, what I really want is a create function that returns a lambda of unit -> unit and I'll transform that into an Action for the Create call I'm using internally.

By on 12/13/2009 10:35 AM ()

I'm having the same problem

I've been trying to do this for days. I have a list of operators or constants and I want to walk through that list and do one thing or another. I can do this easily by wrapping the operators in classes, and using reflection, but I'd rather use F# itself if possible.

1
2
3
4
5
6
7
8
let square x = x * x

let detectFunctionType func =
    match func with
        | :? (_ -> _) -> printfn "a function"
        | _ -> printfn "somethingElse"

let foo = detectFunction square

I get:

Main.fs(23,11): error FS0008: This runtime coercion or type test from type
'a
to
'b -> 'c
involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed.

Thanks in advance for advice!
Andy

By on 12/14/2009 7:33 AM ()

This code snippet may prove informative.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 

let objToObj (x:obj) = x
let square x = x * x

let wrongDetectFunctionType func =
    match box func with
        | :? (_ -> _) -> printfn "a function"  // _ becomes 'obj', cannot generalize compile-time generics to work with runtime reflection
        | _ -> printfn "somethingElse"

wrongDetectFunctionType square
wrongDetectFunctionType objToObj
wrongDetectFunctionType 42

let reallyDetectFunctionType f =
    let mutable t = f.GetType()
    while t.BaseType <> null && t.BaseType <> typeof<obj> do
        t <- t.BaseType 
    if t.IsGenericType && t.GetGenericTypeDefinition() = typedefof<int -> int> then
            printfn "really a function"
    else
        printfn "something else"
        
reallyDetectFunctionType square
reallyDetectFunctionType objToObj
reallyDetectFunctionType 42

That said, I would be careful, it is rare that you would need/want to do this, there is often a better way to achieve an end, depending on exactly what you are up to.

By on 12/14/2009 7:58 AM ()

Dynamic matching with "naked" types is mostly bad as it is often dealing with an existing bad design.

Yet static matching with types as part of the static type definition is a good thing as it can force a higher order invariants.

I hate to keep up the pressure but do keep functors in mind as candidate new features.

Ultimately, if you don't do it, it will be more optimal to generate F# from F# which then means it is easier to transition out of F#

James

By on 12/15/2009 4:53 AM ()

Forgot one thing that's very peculiar. When I put the active pattern as a parameter constraint, it works gloriously...

1
2
3
4
5
let magic (f : _->_) a b= 
    f a b

magic (+) 1 2|> printfn "%A" 
magic (+) 1.0 2.0|> printfn "%A" 
By on 12/14/2009 7:37 AM ()
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