views:

188

answers:

3

I'm trying to make a little function to interpolate between two values with a given increment.

[ 1.0 .. 0.5 .. 20.0 ]

The compiler tells me that this is deprecated, and suggests using ints then casting to float. But this seems a bit long-winded if I have a fractional increment - do I have to divide my start and end values by my increment, then multiple again afterwards? (yeuch!).

I saw something somewhere once about using sequence comprehensions to do this, but I can't remember how.

Help, please.

A: 

Try the following sequence expression

seq { 2 .. 40 } |> Seq.map (fun x -> (float x) / 2.0)
JaredPar
Yes, but how do I generalise that with to a function with arbitrary start, end, increment?
Benjol
+1  A: 

You can also write a relatively simple function to generate the range:

let rec frange(from:float, by:float, tof:float) =
   seq { if (from < tof) then 
            yield from
            yield! frange(from + by, tof) }

Using this you can just write:

frange(1.0, 0.5, 20.0)
Tomas Petricek
It would be the answer, if I could get it to compile!
Benjol
and it won't work for ranges from positive to negative numbers ;)
Benjol
A: 

Updated version of Tomas Petricek's answer, which compiles, and works for decreasing ranges (and works with units of measure): (but it doesn't look as pretty)

let rec frange(from:float<'a>, by:float<'a>, tof:float<'a>) = 
   // (extra ' here for formatting)
   seq { 
        yield from
        if (float by > 0.) then
            if (from + by <= tof) then yield! frange(from + by, by, tof) 
        else   
            if (from + by >= tof) then yield! frange(from + by, by, tof) 
       }

#r "FSharp.Powerpack"
open Math.SI 
frange(1.0<m>, -0.5<m>, -2.1<m>)
Benjol