我创建了一个函数,它将所有整数从1
转换为n
,然后结合相同的序列来创建所有组合的元组序列。因此传递整数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#
中的操作。
这可以通过更惯用的功能方式实现吗?一种更实用的方式通常是更理想的,还是因为其简洁明了而在功能语言中可以接受?
我对f#
相对较新并且正在寻找一些反馈。
答案 0 :(得分:4)
这些循环是所谓的计算表达式的一部分,这对于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'); ...]
答案 1 :(得分:1)
首先,仅仅因为for
并不意味着它不起作用。在此示例中,您将遍历每个元素并生成一个新元素,该元素将转换为新的不可变列表的新元素。这样的功能也被命名为#34; List Comprehension&#34;和Haskell等语言的一部分。势在必行的是循环遍历列表并改变列表。
其次,请记住map
,fold
,filter
等其他函数也只是遍历每个元素,就像for
表达式一样。它们的功能不如for
循环。
第三,即使它是&#34;也不是100%功能&#34;。谁在乎?代码应易于阅读和理解。两个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
循环以提高可读性!