F#中包含多个参数的List.map

Aph*_*hex 1 mapping f# list

这可能是最简单的一个例子.

假设我有一个相当冗长的函数,可以提升整数xn次幂.

let powInt = function
| x,n -> 
  let rec loop acc n =
   match n with
   | 0 -> acc
   | v -> loop (acc * x) (v-1)
  loop 1 n
Run Code Online (Sandbox Code Playgroud)

如果我现在想将整数列表中的每个整数提升到n次幂,我认为F#中的酷List.map函数将是要走的路:

let powIntList (xs: int list) = List.map powInt xs
Run Code Online (Sandbox Code Playgroud)

然而,在最后一个片段中,n功率缺乏作为映射中的参数 - 而int x由函数隐式提取map.

我们如何在这个例子中添加n power参数?

Fyo*_*kin 6

你把你的功能搞定了.

这恰恰就是currying的情况,这是一种以这样一种方式来制定你的功能的技术,即它们可以"逐个"地获取参数.在数学上,这样的函数只接受一个参数,并返回另一个接受第二个参数的函数.像这样的东西:

let curriedPowInt = fun n -> fun x -> powInt (x, n)
Run Code Online (Sandbox Code Playgroud)

这种定义函数的方式很常见.事实上,它是ML语言(其中F#是一个)的本质的核心,它有一个特殊的语法:

let curriedPowInt n x = powInt (x, n)
Run Code Online (Sandbox Code Playgroud)

看看我如何在一行中列出我的参数,用空格分隔它们,比如n x =?这是语法糖fun n -> fun x ->.从逻辑上讲,它定义了一个"逐个"参数的函数,而不是一次作为元组.

既然你有这样的功能,你可以部分应用它 - 也就是说,只给它一个参数,而不是两个:

let pow2 = curriedPowInt 2
Run Code Online (Sandbox Code Playgroud)

这有效,因为 - 记得吗?- 我的函数curriedPowInt接受n并返回另一个函数x.该类型的pow2现在int -> int.这是一个功能,它需要int并将其提升到第二个功率.

当然,你也可以在线使用这个技巧:

let powIntList (xs: int list) = List.map (curriedPowInt n) xs
Run Code Online (Sandbox Code Playgroud)

另外,请注意我如何更改参数的顺序.我把n参数放在第一位,x参数放在最后.这是使您的函数更有用的一般规则:将"最重要"参数放在最后,将"最不重要"放在第一位.List.map例如,看看它自己:它运行的列表是两者的最后一个参数.

最后,我建议不要声明前者,而不是powInt单独curriedPowInt声明.只需将所有功能都用于咖喱.Curried函数更有用.事实上,我很少见到未经证实的函数会有用的场合,我可能也从未见过任何函数.

所以,总结一下:

let powInt n x = 
  let rec loop acc n =
   match n with
   | 0 -> acc
   | v -> loop (acc * x) (v-1)
  loop 1 n

let powIntList (xs: int list) = List.map (powInt n) xs
Run Code Online (Sandbox Code Playgroud)