【问题标题】:A more functional way to create tuples from two arrays从两个数组创建元组的更实用的方法
【发布时间】:2018-03-09 09:40:06
【问题描述】:

我创建了一个函数,它获取从1n 的所有整数,然后与相同的序列组合以创建所有组合的元组序列。所以传递整数2 会给你[(1,1);(1,2);(2,1);(2,2)]

let allTuplesUntil x =
    let primary = seq { 1 .. x }
    let secondary = seq { 1 .. x }
    [for x in primary do
     for y in secondary do
     yield (x,y)]

此实现有效,但它使用内部和外部 for 循环,类似于我在 c# 中所做的。

这可以通过更惯用的功能方式实现吗?功能性更强的方式通常更可取,还是因为其简洁明了而在功能性语言中可以接受?

我对@9​​87654327@ 比较陌生,正在寻找一些反馈。

【问题讨论】:

    标签: f# functional-programming


    【解决方案1】:

    这些循环是所谓的计算表达式的一部分,这对于 F# 来说是非常惯用的。它只是看起来像熟悉的循环。我看不出以这种方式编写的代码有任何问题。如果你想要摆脱循环,你可以将它们隐藏在函数中:

    let cartesianProduct xs ys = 
         xs |> Seq.collect (fun x -> ys |> Seq.map (fun y -> x, y))
    
    cartesianProduct [1;2;3] ['a';'b';'c']
    
    val it : seq<int * char> = seq [(1, 'a'); (1, 'b'); (1, 'c'); (2, 'a'); ...]
    

    【讨论】:

      【解决方案2】:

      首先,仅仅因为有一个for 并不意味着它不起作用。在此示例中,您遍历每个元素并生成一个新元素,该元素将变成新不可变列表的新元素。这种功能也被称为“列表理解”,是 Haskell 等语言的一部分。当务之急是遍历一个列表并改变该列表。

      其次,请记住,mapfoldfilter 等其他函数也只是循环遍历每个元素,例如 for 表达式。它们只是不如for 循环强大。

      第三,即使它“不是 100% 有效”。谁在乎?代码应该易于阅读和理解。两个for 循环的意图很容易理解。

      第四,for 表达式的等效函数通常是 bind 或在本例中为 Seq.collect 函数。你也可以写,这段代码。

      [for x in primary do
       for y in secondary do
       yield (x,y)]
      

      像这样:

      primary |> Seq.collect (fun x ->
      secondary |> Seq.collect (fun y ->
          [x,y]
      ))
      

      为了可读性,我更喜欢 for 循环!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-10-27
        • 2022-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-12
        • 2021-12-14
        相关资源
        最近更新 更多