使用currying多次传递相同的参数链

问题描述 投票:1回答:2

给出此表达式:

// val fn1 : a:'a -> b:'b -> c:'c -> d:'d -> e:'e -> f:'f -> g:'g -> unit
// val fn2 : a:'a -> b:'b -> c:'c -> d:'d -> e:'e -> f:'f -> g:'g -> unit

type T =
  | A
  | B

// val t : T
// val a : 'a
// val b : 'b
// val c : 'c
// val d : 'd
// val e : 'e
// val f : 'f
// val g : 'g

match t with
| A -> fn1 a b c d e f g
| B -> fn2 a b c d e f g

在调用支持currying的函数时,是否有不重复相同参数链的方法?所以你可以写一些像这样的奇怪的东西

(a, b, c, d, e, f, g)
|||||||> (match t with A -> fn1 | B -> fn2)

是否会出现匿名记录的情况?实现此目的的常见做法是什么?

functional-programming f# currying
2个回答
1
投票

仅应用而不是管道?

(match t with
| A -> curried1
| B -> curried2
) 1 2 3 4

FSharp闭包被实现为FSharpFunc<T, TResult>,它具有一个invoke方法,使您无需多个部分应用程序即可调用该方法。

我不建议这样做,但是在极端情况下,您可以使用反射来调用带有参数数组的函数。

let funInvoke fn args =
        let fnType = fn.GetType()
        if not (FSharpType.IsFunction fnType) then
            failwith "Not a function"

        let invoke = Array.head (fnType.GetMethods())
        invoke.Invoke(fn, args)

然后

funInvoke curried1 [|1; 2; 3 ; 4 |]

1
投票

@ Asti的两种解决方案都可以正常工作。我将进一步简化第一个步骤。我更喜欢命名事物,这样我就可以记住它们的含义,所以我会写:]

let funcToCall = match t with | A -> curried1 | B -> curried2
funcToCall 1 2 3 4

但是,我认为注释中有一个有效的观点是您有太多参数。在这种情况下,使用命名记录更有意义:

type FuncParams = { Doors:int; Windows:int; Walls:int; Chimneys:int; .... }

let arg = { Doors=1; Windows=2; Walls=3; Chimneys=4; ... }
match t with A -> curried1 arg | B -> curried2 arg
    
© www.soinside.com 2019 - 2024. All rights reserved.