Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating a sequence of points in F# in a one-liner

I find myself frequently implementing the same (x, y) pattern:

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

Wouldn't out there be a simple one-liner for this, by chance? Of course I could just write this very same function in just one line, but I feel its readability would suffer quite a bit:

let rectangleSizes = seq { for w = 1 to width do for h = 1 to height do yield (w, h) }
like image 519
devoured elysium Avatar asked Mar 05 '14 08:03

devoured elysium


People also ask

How do you find the sequence of a generating function?

To find the generating function for a sequence means to find a closed form formula for f(x), one that has no ellipses. (for all x less than 1 in absolute value). Problem: Suppose f(x) is the generating function for a and g(x) is the generating function for b.

What is seq in F#?

The type seq<'T> is a type abbreviation for IEnumerable<'T> . This means that any type that implements the generic System. Collections. Generic. IEnumerable<'T> , which includes arrays, lists, sets, and maps in F#, and also most .

Which function is used to generate sequences in R?

seq() function in R Language is used to create a sequence of elements in a Vector.


Video Answer


3 Answers

If I had that initialization all the time I would define my own operator:

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)}

But this shadows the original (..) operator, however you can use another operator name or a function. Also there is a trick to avoid shadowing the original operator definition.

Alternatively if you use a library which implements Applicative Functors like F#+ you can define it in one single line as:

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

Note: The function fun x y -> (x, y) is usually called tuple2

#r @"FsControl.Core.dll"
#r @"FSharpPlus.dll"

open FSharpPlus
let tuple2 a b = (a,b)
let width, height = 5,7

let rectangleSizes = tuple2 <!> {1..width} <*> {1..height}
like image 99
Gus Avatar answered Oct 24 '22 00:10

Gus


You could use the fact that 2D arrays implement IEnumerable, which can be converted to IEnumerable<'T> (aka seq<'T>) using Seq.cast:

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

Edit: This will create an array that stores all elements though, whereas your initial implementation generates them as needed. If your width and height are big, this may consume too much memory.

like image 2
Tarmil Avatar answered Oct 24 '22 02:10

Tarmil


You could save a teensy bit of space by :

let rectangleSizes = seq {
    for w = 1 to width do 
       for h = 1 to height -> (w, h)
}
like image 2
Fsharp Pete Avatar answered Oct 24 '22 02:10

Fsharp Pete