-
-
Save gusty/47b53b21548304730341fe4799a1f050 to your computer and use it in GitHub Desktop.
#nowarn "0042" | |
let inline retype (x: 'T) : 'U = (# "" x: 'U #) | |
open System | |
type Curry = | |
static member inline Invoke f = | |
let inline call_2 (a: ^a, b: ^b) = ((^a or ^b) : (static member Curry: _*_ -> _) b, a) | |
call_2 (Unchecked.defaultof<Curry>, Unchecked.defaultof<'t>) (f: 't -> 'r) : 'args | |
static member inline Curry (t: 't, _: Curry) = fun f t1 t2 t3 t4 t5 t6 t7 -> | |
Curry.Invoke (fun tr -> | |
let (t1: 't1) = if false then (^t : (member Item1 : 't1) t) else t1 | |
let (t2: 't2) = if false then (^t : (member Item2 : 't2) t) else t2 | |
let (t3: 't3) = if false then (^t : (member Item3 : 't3) t) else t3 | |
let (t4: 't4) = if false then (^t : (member Item4 : 't4) t) else t4 | |
let (t5: 't5) = if false then (^t : (member Item5 : 't5) t) else t5 | |
let (t6: 't6) = if false then (^t : (member Item6 : 't6) t) else t6 | |
let (t7: 't7) = if false then (^t : (member Item7 : 't7) t) else t7 | |
let (tr: 'tr) = if false then (^t : (member Rest : 'tr) t) else tr | |
f (Tuple<_,_,_,_,_,_,_,_>(t1, t2, t3, t4, t5, t6, t7, tr) |> retype)) | |
static member Curry (x: Tuple<'t1> , _: Curry) = fun f t1 -> f (Tuple<_> t1) | |
static member Curry ((t1, t2) , _: Curry) = fun f t1 t2 -> f (t1, t2) | |
static member Curry ((t1, t2, t3) , _: Curry) = fun f t1 t2 t3 -> f (t1, t2, t3) | |
static member Curry ((t1, t2, t3, t4) , _: Curry) = fun f t1 t2 t3 t4 -> f (t1, t2, t3, t4) | |
static member Curry ((t1, t2, t3, t4, t5) , _: Curry) = fun f t1 t2 t3 t4 t5 -> f (t1, t2, t3, t4, t5) | |
static member Curry ((t1, t2, t3, t4, t5, t6) , _: Curry) = fun f t1 t2 t3 t4 t5 t6 -> f (t1, t2, t3, t4, t5, t6) | |
static member Curry ((t1, t2, t3, t4, t5, t6, t7), _: Curry) = fun f t1 t2 t3 t4 t5 t6 t7 -> f (t1, t2, t3, t4, t5, t6, t7) | |
let inline curry f t = Curry.Invoke f t | |
/////////// | |
// TESTS // | |
/////////// | |
let f2 (x, y) = [x + y] | |
let f3 (x, y, z) = [x + y + z] | |
let f7 (t1, t2, t3, t4, t5, t6, t7) = [t1+t2+t3+t4+t5+t6+t7] | |
let f8 (t1, t2, t3, t4, t5, t6, t7: float, t8: char) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8] | |
let f9 (t1, t2, t3, t4, t5, t6, t7: float, t8: char, t9: decimal) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9] | |
let f15 (t1, t2, t3, t4, t5, t6, t7: float, t8: char, t9: decimal, t10, t11, t12, t13, t14, t15) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9+t10+t11+t12+t13+t14+t15] | |
let f16 (t1, t2, t3, t4, t5, t6, t7: float, t8: char, t9: decimal, t10, t11, t12, t13, t14, t15, t16) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9+t10+t11+t12+t13+t14+t15+t16] | |
let f17 (t1, t2, t3, t4, t5, t6, t7: float, t8: char, t9: decimal, t10, t11, t12, t13, t14, t15, t16, t17) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9+t10+t11+t12+t13+t14+t15+t16+t17] | |
let f1 (x:Tuple<_>) = [x.Item1] | |
let x2 = curry f2 1 2 | |
let x3 = curry f3 1 2 3 | |
let x7 = curry f7 1 2 3 4 5 6 7 | |
let x8 = curry f8 1 2 3 4 5 6 7. '8' | |
let x9 = curry f9 1 2 3 4 5 6 7. '8' 9M | |
let x15 = curry f15 1 2 3 4 5 6 7. '8' 9M 10 11 12 13 14 15 | |
let x16 = curry f16 1 2 3 4 5 6 7. '8' 9M 10 11 12 13 14 15 16 | |
let x17 = curry f17 1 2 3 4 5 6 7. '8' 9M 10 11 12 13 14 15 16 17 | |
let x1 = curry f1 100 |
open System | |
type Uncurry = | |
static member inline Invoke f t = | |
let inline call_2 (a: ^a, b: ^b) = ((^a or ^b) : (static member Uncurry: _*_ -> _) b, a) f | |
call_2 (Unchecked.defaultof<Uncurry>, t) : 'r | |
static member inline Uncurry (t: 't, _: Uncurry) = fun f -> | |
let (t1: 't1) = (^t : (member Item1 : 't1) t) | |
let (t2: 't2) = (^t : (member Item2 : 't2) t) | |
let (t3: 't3) = (^t : (member Item3 : 't3) t) | |
let (t4: 't4) = (^t : (member Item4 : 't4) t) | |
let (t5: 't5) = (^t : (member Item5 : 't5) t) | |
let (t6: 't6) = (^t : (member Item6 : 't6) t) | |
let (t7: 't7) = (^t : (member Item7 : 't7) t) | |
let (tr: 'tr) = (^t : (member Rest : 'tr) t) | |
Uncurry.Invoke (f t1 t2 t3 t4 t5 t6 t7) tr | |
static member Uncurry (x: Tuple<'t1> , _: Uncurry) = fun f -> f x.Item1 | |
static member Uncurry ((t1, t2) , _: Uncurry) = fun f -> f t1 t2 | |
static member Uncurry ((t1, t2, t3) , _: Uncurry) = fun f -> f t1 t2 t3 | |
static member Uncurry ((t1, t2, t3, t4) , _: Uncurry) = fun f -> f t1 t2 t3 t4 | |
static member Uncurry ((t1, t2, t3, t4, t5) , _: Uncurry) = fun f -> f t1 t2 t3 t4 t5 | |
static member Uncurry ((t1, t2, t3, t4, t5, t6) , _: Uncurry) = fun f -> f t1 t2 t3 t4 t5 t6 | |
static member Uncurry ((t1, t2, t3, t4, t5, t6, t7), _: Uncurry) = fun f -> f t1 t2 t3 t4 t5 t6 t7 | |
let inline uncurry f t = Uncurry.Invoke f t | |
/////////// | |
// TESTS // | |
/////////// | |
let f2 x y = [x + y] | |
let f3 x y z = [x + y + z] | |
let f7 a b c d e f g = [a + b + c + d + e + f + g] | |
let f8 t1 t2 t3 t4 t5 t6 (t7: float) (t8: char) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8] | |
let f9 t1 t2 t3 t4 t5 t6 (t7: float) (t8: char) (t9: decimal) = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9] | |
let f12 t1 t2 t3 t4 t5 t6 (t7: float) (t8: char) (t9: decimal) t10 t11 t12 = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9+t10+t11+t12] | |
let f15 t1 t2 t3 t4 t5 t6 (t7: float) (t8: char) (t9: decimal) t10 t11 t12 t13 t14 t15 = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9+t10+t11+t12+t13+t14+t15] | |
let f16 t1 t2 t3 t4 t5 t6 (t7: float) (t8: char) (t9: decimal) t10 t11 t12 t13 t14 t15 t16 = [t1+t2+t3+t4+t5+t6+ int t7 + int t8+ int t9+t10+t11+t12+t13+t14+t15+t16] | |
let x2 = uncurry f2 (1, 2) | |
let x3 = uncurry f3 (1, 2, 3) | |
let x7 = uncurry f7 (1, 2, 3, 4, 5, 6, 7) | |
let x8 = uncurry f8 (1, 2, 3, 4, 5, 6, 7. , '8') | |
let x9 = uncurry f9 (1, 2, 3, 4, 5, 6, 7. , '8', 9M) | |
let x12 = uncurry f12 (1, 2, 3, 4, 5, 6, 7. , '8', 9M, 10 , 11, 12) | |
let x15 = uncurry f15 (1, 2, 3, 4, 5, 6, 7. , '8', 9M, 10 , 11, 12, 13, 14, 15) | |
let x16 = uncurry f16 (1, 2, 3, 4, 5, 6, 7. , '8', 9M, 10 , 11, 12, 13, 14, 15, 16) | |
let x1 = uncurry id (Tuple<_> 1) |
I owe the community long time a blog post about all these polyvariadic functions.
The if false
statements are a reflection of my laziness to write by hand (at least try to, it might not be possible) the whole signature with all the constraints.
For instance this let (t1: 't1) = if false then (^t : (member Item1 : 't1) t) else t1
pretends that it will extract the item1 from the unused parameter, but it won't, because it's unused and because otherwise it will throw a null exception, the goal is to drive type inference to add the Item1
constraint to the signature, though in this case requiring Rest
alone might be good enough, not sure, because it also makes the "link" between the constraints and the 't1
type. But of course, there should be a way to write all this directly in the signature.
PS: planning to add this to F#+ -> fsprojects/FSharpPlus#155
Cool idea! This could be useful in many scenarios, but hard to grasp, maybe you could write a blog post about this technique?
And I'm curious, why are the repeated
if false
required? Fooling the compiler?