代码之家  ›  专栏  ›  技术社区  ›  Dax Fohl

如何用f或任何函数语言表示第二个(或第三个、第四个,…)参数?

  •  12
  • Dax Fohl  · 技术社区  · 15 年前

    我刚开始使用f并了解如何使用curring将第一个参数预加载到函数。但是,对于第二个、第三个或其他任何参数,如何处理呢?命名参数会使这更容易吗?是否有其他函数语言具有命名参数的功能,或者有其他方法可以使当前的参数顺序不受影响?

    5 回复  |  直到 6 年前
        1
  •  18
  •   Brian    15 年前

    通常只使用lambda:

    fun x y z -> f x y 42
    

    是类似“f”的函数,但第三个参数绑定到42。

    你也可以使用组合器(就像有人在评论中提到过哈斯克尔的“flip”),它可以重新排序参数,但我有时会觉得很混乱。

    请注意,大多数课程化函数都是这样编写的,因此最可能部分应用的参数首先出现。

    f具有方法的命名参数(不允许绑定函数值),但这些名称适用于“tupled”参数。命名的curried参数没有多大意义;如果我有一个两参数的curried函数“f”,我希望给出

    let g = f
    let h x y = f x y
    

    那么“g”或“h”可以替换为“f”,但“named”参数不一定使其为真。也就是说,“命名参数”与语言设计的其他方面的交互很差,我个人不知道“命名参数”与“一流的课程函数值”交互良好的现成设计。

        2
  •  5
  •   Chuck    15 年前

    ocaml是f所基于的语言,它有标记(和可选)的参数,可以按任意顺序指定,您可以根据这些参数的名称部分应用函数。我不相信F有这个功能。

    你可以尝试创造一些像哈斯克尔的 flip 功能。创建在参数列表中进一步跳转参数的变体不应该太难。

    let flip f a b = f b a
    let flip2 f a b c = f b c a
    let flip3 f a b c d = f b c d a
    
        3
  •  5
  •   ttsiodras    10 年前

    只是为了完整性——既然您询问了其他功能语言——这就是您在ocaml中的做法,可以说是f的“母亲”:

    $ ocaml
    # let foo ~x ~y = x - y ;;
    val foo : x:int -> y:int -> int = <fun>
    # foo 5 3;;
    - : int = 2
    # let bar = foo ~y:3;;
    val bar : x:int -> int = <fun>
    # bar 5;;
    - : int = 2
    

    因此,在ocaml中,只需使用参数的名称,就可以对所需的任何命名参数进行硬编码。( y 在上面的例子中)。

    正如您发现的那样,Microsoft选择不实现此功能…在我看来,这不是“与语言设计其他方面的不良互动”…这更有可能是因为这需要额外的努力(在语言实现中)以及将语言带到世界上所造成的延迟——事实上,只有少数人会(a)意识到OCAML的“逐步下降”,(b)无论如何使用命名函数参数。

    我是少数人,确实使用它们——但它确实是F中的一个很容易模仿的地方函数绑定:

    let foo x y = x - y
    let bar x = foo x 3
    bar ...
    
        4
  •  4
  •   codeape    15 年前

    在python中,可以使用 functools.partial 或者是λ。python已经命名了参数。 功能工具.部分 可用于指定第一个位置参数以及任何命名参数。

    from functools import partial
    
    def foo(a, b, bar=None):
        ...
    
    f = partial(foo, bar='wzzz') # f(1, 2) ~ foo(1, 2, bar='wzzz')
    f2 = partial(foo, 3)         # f2(5) ~ foo(3, 5)
    
    f3 = lambda a: foo(a, 7)     # f3(9) ~ foo(9, 7)
    
        5
  •  3
  •   phoog    6 年前

    可以不声明就这么做,但我同意 Brian 那个 a lambda or a custom function is probably a better solution .

    我发现,我最经常希望这部分应用除法或减法。

    > let halve = (/) >> (|>) 2.0;;
    > let halfPi = halve System.Math.PI;;
    
    val halve : (float -> float)
    val halfPi : float = 1.570796327
    

    概括起来,我们可以声明一个函数 applySecond 以下内容:

    > let applySecond f arg2 = f >> (|>) arg2;;
    val applySecond : f:('a -> 'b -> 'c) -> arg2:'b -> ('a -> 'c)
    

    为了遵循逻辑,可能有助于定义函数,因此:

    > let applySecond f arg2 =
    -     let ff = (|>) arg2
    -     f >> ff;;
    val applySecond : f:('a -> 'b -> 'c) -> arg2:'b -> ('a -> 'c)
    

    现在 f 是来自的函数 'a 'b -> 'c . 这是由 ff ,函数来自 'B& gt;c 'c 这是由于 arg2 转发给管道运营商。此函数适用于 'b 传递的值 精氨酸 它的论点。所以当我们作曲时 f 具有 FF公司 ,我们得到一个函数 “A” C 使用给定值 争论,这正是我们想要的。

    将上面的第一个示例与以下示例进行比较:

    > let halve f = f / 2.0;;
    > let halfPi = halve System.Math.PI;;
    
    val halve : f:float -> float
    val halfPi : float = 1.570796327
    

    还要比较这些:

    let filterTwoDigitInts = List.filter >> (|>) [10 .. 99]
    let oddTwoDigitInts = filterTwoDigitInts ((&&&) 1 >> (=) 1)
    let evenTwoDigitInts = filterTwoDigitInts ((&&&) 1 >> (=) 0)
    
    let filterTwoDigitInts f = List.filter f [10 .. 99]
    let oddTwoDigitInts = filterTwoDigitInts (fun i -> i &&& 1 = 1)
    let evenTwoDigitInts = filterTwoDigitInts (fun i -> i &&& 1 = 0)
    

    或者,比较:

    let someFloats = [0.0 .. 10.0]
    let theFloatsDividedByFour1 = someFloats |> List.map ((/) >> (|>) 4.0)
    let theFloatsDividedByFour2 = someFloats |> List.map (fun f -> f / 4.0)
    

    lambda版本似乎更容易阅读。