6 people like it.

Creating named parameters

The snippet shows how to define the "=>" operator in F# so that it can be used for creating named parameters for dynamic API.

 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: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
// This does not work - no automatic conversion to 'obj'
let objs1 = [1; "hi"]
// ...but it works if compiler knows the type in advance
let objs2 : obj list = [1; "hi"]

// But, that only works for simple types - so even if we
// know the type in advance, it will not work for tuples :-(
let objs2 : (string*obj) list = [("hi", 1)]

// We could define our own tuple type to make this possible
// with a less generic base class - here, I just make base
// class generic in key, but not in value
type Tuple<'K> =  
  abstract Key : 'K
  abstract Value : obj

// And then we have fully generic tuple that implements the
// less-generic variant (and boxes the value)
type Tuple<'K, 'V> = 
  | KV of 'K * 'V
  member x.Key = let (KV(k, v)) = x in k
  member x.Value = let (KV(k, v)) = x in v
  interface Tuple<'K> with
    member x.Key = let (KV(k, v)) = x in k
    member x.Value = let (KV(k, v)) = x in box v
    
// Builds the more-generic version of the tuple
let (=>) k v = KV(k, v)

// This does not work, because we are creating list that
// contains 'Tuple<string, int>' and 'Tuple<string, string>'
let pars = ["x" => 1; "y" => "42"]

// But we can make it work if we know the type in advance
let namedPars (p:list<Tuple<string>>) = p
let pars = namedPars ["x" => 1; "y" => "42"]

// Note that this will NOT work
["x" => 1; "y" => "42"] |> namedPars

// It plays nicely with ParamArray too
type R() =
  static member plot(s:string, [<System.ParamArray>] pars:Tuple<string>[]) =
    printfn "%s - %A" s pars

// This gives us what Howard suggested!
R.plot("sin", "x" => 1, "y" => "42")

// But we can still write functions that require Tuple<string, int> 
// rather than tuple with any type of values
let fromNums (nums:list<Tuple<string, int>>) = nums

// Fine
fromNums ["a" => 1; "b" => 3]
// Not allowed
fromNums ["a" => 1; "b" => 'a']
val objs1 : int list

Full name: Script.objs1
val objs2 : obj list

Full name: Script.objs2
type obj = System.Object

Full name: Microsoft.FSharp.Core.obj
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val objs2 : (string * obj) list

Full name: Script.objs2
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
type Tuple<'K> =
  interface
    abstract member Key : 'K
    abstract member Value : obj
  end

Full name: Script.Tuple<_>
abstract member Tuple.Key : 'K

Full name: Script.Tuple`1.Key
abstract member Tuple.Value : obj

Full name: Script.Tuple`1.Value
Multiple items
type Tuple<'K> =
  interface
    abstract member Key : 'K
    abstract member Value : obj
  end

Full name: Script.Tuple<_>

--------------------
type Tuple<'K,'V> =
  | KV of 'K * 'V
  interface Tuple<'K>
  member Key : 'K
  member Value : 'V

Full name: Script.Tuple<_,_>
union case Tuple.KV: 'K * 'V -> Tuple<'K,'V>
val x : Tuple<'K,'V>
member Tuple.Key : 'K

Full name: Script.Tuple`2.Key
val k : 'K
val v : 'V
member Tuple.Value : 'V

Full name: Script.Tuple`2.Value
override Tuple.Key : 'K

Full name: Script.Tuple`2.Key
override Tuple.Value : obj

Full name: Script.Tuple`2.Value
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
val k : 'a
val v : 'b
val pars : Tuple<string,int> list

Full name: Script.pars
val namedPars : p:Tuple<string> list -> Tuple<string> list

Full name: Script.namedPars
val p : Tuple<string> list
val pars : Tuple<string> list

Full name: Script.pars
type R =
  new : unit -> R
  static member plot : s:string * [<ParamArray>] pars:Tuple<string> [] -> unit

Full name: Script.R
static member R.plot : s:string * [<System.ParamArray>] pars:Tuple<string> [] -> unit

Full name: Script.R.plot
val s : string
namespace System
Multiple items
type ParamArrayAttribute =
  inherit Attribute
  new : unit -> ParamArrayAttribute

Full name: System.ParamArrayAttribute

--------------------
System.ParamArrayAttribute() : unit
val pars : Tuple<string> []
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
static member R.plot : s:string * [<System.ParamArray>] pars:Tuple<string> [] -> unit
val fromNums : nums:Tuple<string,int> list -> Tuple<string,int> list

Full name: Script.fromNums
val nums : Tuple<string,int> list
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Raw view Test code New version

More information

Link:http://fssnip.net/k9
Posted:10 years ago
Author:Tomas Petricek
Tags: r provider