stephensong
stephensong

Reputation: 277

Is there an F# equivalent to this C# extension method?

I find the following C# extension method very useful:

public static bool In<T>(this T x, params T[] xs)
{
    return xs.Contains(x);
}

allowing for C# calls such as

var s = "something else";
var rslt = s.In("this","that","other") ? "Yay" : "Boo";

and

var i = 1;
var rslt = i.In(1,2,3) ? "Yay" : "Boo";

I have been trying to come up with an F# (near-)equivalent, allowing e.g.:

let s = "something else"
let rslt = if s.In("this","that","other") then "Yay" else "Boo"

It seems like I would need something like:

type 'T with

    static member this.In([ParamArray] xs : 'T  )
        {
            return xs.Contains(x);
        }

but that is not legal F# syntax. I can't see how to declare a extension method on a generic class in F#. Is it possible? Or is there a better way to achieve similar results? (I imagine I could just link in the C# project and call it from F#, but that would be cheating! :-)

The best I could come up with was:

let inline In (x : 'a, [<ParamArray>] xs : 'a[]) = Array.Exists( xs, (fun y -> x = y) )  

which I expected to allow for calls like (which are not really acceptable anyway imho):

if In(ch, '?', '/') then "Yay" else "Boo"

but in fact required:

if In(ch, [| '?'; '/' |]) then "Yay" else "Boo"

implying that the ParamArray attribute is being ignored (for reasons I've yet to fathom).

Upvotes: 2

Views: 133

Answers (1)

stephensong
stephensong

Reputation: 277

Fwiw, the latest version of F# (3.1) contains exactly what I was after (yay!):

[<Extension>] 
type ExtraCSharpStyleExtensionMethodsInFSharp () = 

    [<Extension>] 
    static member inline In(x: 'T, xs: seq<'T>) = xs |> Seq.exists (fun o -> o = x)

    [<Extension>] 
    static member inline Contains(xs: seq<'T>, x: 'T) = xs |> Seq.exists (fun o -> o = x)

    [<Extension>] 
    static member inline NotIn(x: 'T, xs: seq<'T>) = xs |> Seq.forall (fun o -> o <> x)

providing usages as

 if s.In(["this","that","other"]) then ....
 if (["this","that","other"]).Contains(s) then ...

etc.

Upvotes: 2

Related Questions