.net 在一条直线上生成F#中的点序列

.net 在一条直线上生成F#中的点序列,.net,f#,functional-programming,.net,F#,Functional Programming,我发现自己经常实现相同的(x,y)模式: let rectangleSizes = seq { for w = 1 to width do for h = 1 to height do yield (w, h) } 难道不是有一个简单的一行这样的机会吗?当然,我可以只在一行中编写相同的函数,但我觉得它的可读性会受到很大影响: let rectangleSizes = seq { for w = 1 to width do for h = 1 to

我发现自己经常实现相同的
(x,y)
模式:

let rectangleSizes = seq {
    for w = 1 to width do
        for h = 1 to height do
            yield (w, h)
}
难道不是有一个简单的一行这样的机会吗?当然,我可以只在一行中编写相同的函数,但我觉得它的可读性会受到很大影响:

let rectangleSizes = seq { for w = 1 to width do for h = 1 to height do yield (w, h) }

您可以使用2D数组实现
IEnumerable
,可以使用
Seq.cast
将其转换为
IEnumerable
):

let rectangleSizes = Array2D.initBased 1 1 width height (fun w h -> (w, h)) |> Seq.cast<int * int>
let rectangleSizes=Array2D.initBased 1 1宽度-高度(fun w h->(w,h))|>Seq.cast

编辑:这将创建一个存储所有元素的数组,而您的初始实现会根据需要生成它们。如果您的宽度和高度都很大,这可能会消耗太多内存。

如果我一直进行初始化,我会定义自己的运算符:

let (..) (x0,y0) (xn,yn) =  
    seq {
        for x = x0 to xn do
            for y = y0 to yn do
                yield (x, y)}

let rectangleSizes = {(1,1) .. (5,7)}
但这会影响原始的
(..)
运算符,但是您可以使用其他运算符名称或函数。此外,还有一个避免隐藏原始运算符定义的方法

或者,如果您使用实现应用程序函子的库,您可以在一行中将其定义为:

let rectangleSizes = (fun x y -> (x, y)) <!> {1..width} <*> {1..height}

您可以使用
List.collect
List.map

let rectangleSizes = [1..width] |> List.collect (fun x -> [1..height] |> List.map (fun y -> (x,y)))
但在我看来,这并不像您使用
seq
构造函数的原始解决方案那样可读(而且评估非常迫切)。我也更喜欢@Gustavo使用重载运算符

更新:

使用序列的延迟评估:

let rectangleSizes = {1..width} |> Seq.collect (fun x -> {1..height} |> Seq.map (fun y -> (x,y)))

您可以通过以下方式节省少量空间:

let rectangleSizes = seq {
    for w = 1 to width do 
       for h = 1 to height -> (w, h)
}

另一种可能性是写作

Seq.init width (fun w -> Seq.init height (fun h -> (w+1,h+1))) |> Seq.concat


我认为没有任何技巧可以避免对库定义的range操作符进行阴影处理,因此这根本不是一个好主意。理论上,您可以在类型上提供用户定义的
op_范围
,但如果您尝试使用它,您将在绑定中获得意外的符号“..”。错误。可能是因为规范的§3.6规定它被视为一个符号关键字。@kaefer不管怎么说,元组是一个已经定义的类型,但仍然有一个技巧可以使它工作,我刚刚上传了一个示例,它也会链接到答案。由于您使用List.map和List.collect函数,因此评估非常迫切,改用Seq.map和Seq.collect函数。你也需要用花括号而不是方括号。你是对的,我不知道序列也存在构造函数
n..m
。我对第二个代码段进行了全部编辑,因为它让我的眼睛流血,然后我意识到这对你的问题至关重要:一个小小的简化:
Seq.collect id
Seq.concat
。我怎么没有意识到?谢谢!:)
Seq.init width (fun w -> Seq.init height (fun h -> (w+1,h+1))) |> Seq.concat
seq [1 .. width] |> Seq.collect (fun w -> Seq.init height (fun h -> (w,h+1)))