F# 用计算表达式追加多个列表

F# 用计算表达式追加多个列表,f#,functional-programming,F#,Functional Programming,我有一个函数,它生成一些元素并在列表中返回它们。函数接受一个参数来过滤返回的元素。函数如下所示: let create x = [1..1000] |> List.filter (fun c -> (c % x) = 0) 现在我想用多个条件调用这个函数,并将所有结果附加到一个列表中 起初,我想这样做: let result = (create 100) |> List.append (create 300) |> L

我有一个函数,它生成一些元素并在列表中返回它们。函数接受一个参数来过滤返回的元素。函数如下所示:

let create x = [1..1000] |> List.filter (fun c -> (c % x) = 0)
现在我想用多个条件调用这个函数,并将所有结果附加到一个列表中

起初,我想这样做:

let result = (create 100) 
            |> List.append (create 300) 
            |> List.append (create 500) 
            |> List.append (create 3)
printf "%A" result
但是我发现这个解决方案在使用
List.append
表达式时并不优雅和重复

我尝试了第二种解决方案:

let result = [100; 300; 500; 3] |> List.map (fun c -> create c) 
                                |> List.reduce (fun acc c -> acc |> List.append c)
printf "%A" result
这个解决方案更简洁,但我不喜欢它。我发现它不那么清晰,更难猜测我们试图实现什么

因此,我正在寻找第三种解决方案,并尝试使用计算表达式实现一种新的解决方案:

type AppendBuilder() =
    member this.Bind (x, f) = f x |> List.append x
    member this.Return x = x
然后像这样使用它:

let append = new AppendBuilder()
let result = append {
    let! a = create 100
    let! b = create 300
    let! c = create 500
    let! d = create 3

    return []
}
printf "%A" result
最后一个解决方案有效,我更喜欢它。我发现它更清晰,更容易理解我们在做什么,并且没有repetive List.append表达式。但还是有问题。我不喜欢
return[]
部分,这似乎不自然,也不清楚。但要使其发挥作用,这一技巧是必要的

第三种解决方案是我最喜欢的,但我不确定这是解决我问题的正确方法。它解决了问题,我得到了正确的结果,但我不确定这是否是正确的方法


我能保留第三种解决方案而不引起对我意图的混淆吗?解决方案是否足够清晰,可以保持原样?我正在寻找一种更专注于操作的解决方案(这里调用
create x
),而不是寄生在代码中的重复表达式(这里调用
List.append
)。

您可以从
seq
计算的惰性中获益:

seq {
    yield! create 100
    yield! create 300
    yield! create 500
    yield! create 3
} |> List.ofSeq

然后使用list.ofSeq

计算列表如果第三个是您最喜欢的版本,那么您可能需要使用列表理解:

let result = 
    [ yield! create 100
      yield! create 300
      yield! create 500
      yield! create 3 ]
值得注意的是:使用Python列表后,我确实发现它们更友好,因为您可以使用值
1000
,而不是值
1001

如果您的
create
函数始终是
step函数
,则使用List的内置功能更有意义。如果您计划使用一个
create
函数,但该函数不能利用List的内置功能,那么注释by更有意义

let result = 
    [100;300;500;3] 
    |> List.collect create
注释中建议的一种变体是允许
create
函数的值作为参数输入

let makeList parms =
    parms
    |> List.collect create
然后用作

let result = makeList [100;300;500;3]
甚至


由于这是作为答复提出的:

最简单的方法是使用
List.collect
,它可以在一个步骤中映射和组合列表

本例中的解决方案如下所示

[100;300;500;3] |> List.collect create

那我更喜欢@JohnPalmer的解决方案,而不是发布的所有答案。它充分利用了库函数,与所有已发布的解决方案相比,它允许参数(
[100;300;500;3]
)来自上一个计算步骤。是的,最好将您的计算表示为数据转换作为起点,如果有其他要求(例如性能),则从该角度出发感兴趣的是:并不是因为这个问题,而是因为重构功能代码的概念。
let makeList = List.collect create
[100;300;500;3] |> List.collect create