I could really do with some help with tail call optimization in F#.
I am trying to parse a tree like structure and perform a calculation on each leaf.
The function I'm having problems with is calcLength
type Location = float * float
type Radius = float
type Width = float
type Angle = float
type Primitive =
| Circle of Location * Radius
| Ellipse of Location * Radius * Radius
| Square of Location * Width * Angle
| MultiPrimitive of Primitive List
type Primitive with
member x.Length =
let rec calcLength x =
match x with
| Circle (_,r) -> System.Math.PI * r * 2.
| Ellipse (_,r1,r2) -> System.Math.PI * 2. * sqrt( (r1 * r1 ) + (r2 * r2 ) / 2.)
| Square (_, w,_) -> w * 4.
| MultiPrimitive [] -> 0.
| MultiPrimitive (head::tail) -> calcLength (MultiPrimitive tail) + (calcLength head)
[<Fact>]
let ``test discriminated unions``() =
let pattern = MultiPrimitive(
[
MultiPrimitive(
[
MultiPrimitive(
[
Square( (10.,10.), 10., 45. );
Circle( (3.,7.), 3. );
Circle( (7.,7.), 3. );
Square( (5.,2.), 3., 45. );
] );
Square( (10.,10.), 10., 45. );
Circle( (3.,7.), 3. );
Circle( (7.,7.), 3. );
Square( (5.,2.), 3., 45. );
] );
Square( (10.,10.), 10., 45. );
Circle( (3.,7.), 3. );
Circle( (7.,7.), 3. );
Square( (5.,2.), 3., 45. );
] )
let r = pattern.Length
I attempted to use the continuation approach with the following:
let rec calcLength x f =
match x with
| Circle (_,r) -> f() + System.Math.PI * r * 2.
| Ellipse (_,r1,r2) -> f() + System.Math.PI * 2. * sqrt( (r1 * r1 ) + (r2 * r2 ) / 2.)
| Square (_, w,_) -> f() + w * 4.
| MultiPrimitive [] -> f()
| MultiPrimitive (head::tail) -> calcLength head (fun () -> calcLength(MultiPrimitive tail) f )
calcLength x (fun () -> 0.)
But stepping through with the debugger showed the stack growing, any help would be Really appreciated.
The usual way to use CPS is to pass the result to the given continuation:
let rec calcLength x k =
match x with
| Circle (_,r) -> k (System.Math.PI * r * 2.)
| Ellipse (_,r1,r2) -> k (System.Math.PI * 2. * sqrt( (r1 * r1 ) + (r2 * r2 ) / 2.))
| Square (_, w,_) -> k (w * 4.)
| MultiPrimitive [] -> k 0.
| MultiPrimitive (head::tail) -> (calcLength head (fun h -> calcLength(MultiPrimitive tail) (fun t -> k (h + t))))
so in the MultiPrimitive case you need to pass another continuation to deal with the result from calculating the head.
Related
I'm learning F# by implementing a board game engine. In accordance with the principle that invalid states should not be representable, I want to create a type which represents (x, y) coordinates (with x and y integers) where x and y must satisfy 0 <= x <= n and 0 <= y <= m. Creating an instance that does not satisfy those inequalities shouldn't compile. Is this possible?
I don't think compile time assurances on values like this are possible.
I would handle this with a private constructor and the Result or Option type depending whether I wanted to propagate error information.
type Position =
private {
X: int
Y: int
}
static member TryNew(x, y) =
if x >= 0 && x <= 10 then
if y >= 0 && y <=10 then
Ok {
X = x
Y = y
}
else
Error $"Supplied y ({y}) must be between 0 and 10"
else
Error $"Supplied x ({x}) must be between 0 and 10"
module Position =
let moveX1 pos =
Position.TryNew(pos.X + 1, pos.Y)
This does create the issue where Results are now everywhere in your code but they don't have to be visible or cause you a lot of typing. This problem is precisely what computation expression libraries e.g. FsToolkit.ErrorHandling are designed to eliminate.
let example =
result {
let! start = Position.TryNew(0,0)
let! next = start |> moveX1
}
There's no way to do this that takes integers as input, but it can be done with a type that only provides integers as output:
type XCoord = X0 | X1 | X2 with
member this.Int =
match this with
| X0 -> 0
| X1 -> 1
| X2 -> 2
static member (-)(xa : XCoord, xb: XCoord) =
xa.Int - xb.Int
type YCoord = Y0 | Y1 | Y2 with
member this.Int =
match this with
| Y0 -> 0
| Y1 -> 1
| Y2 -> 2
static member (-)(ya : YCoord, yb: YCoord) =
ya.Int - yb.Int
type Point = MkPoint of (XCoord * YCoord) with
member this.Ints =
let (MkPoint (x, y)) = this
x.Int, y.Int
static member (-)((MkPoint (ax, ay)), (MkPoint (bx, by))) =
ax - bx, ay - by
let ptA = MkPoint (X0, Y1)
let ptB = MkPoint (X2, Y0)
printfn "%A" ptA.Ints
printfn "%A" ptB.Ints
printfn "%A" (ptA - ptB)
I think this would be pretty clunky to use in practice, but it might work, depending on exactly what you want to do with it. I guess it's a case of "careful what you ask for". 😀
I am trying to write a tetranacci function using F# as efficiently as possible the first solution I came up with was really inefficient. can you help me come up with a better one? How would i be able to implement this in linear time?
let rec tetra n =
match n with
| 0 -> 0
| 1 -> 1
| 2 -> 1
| 3 -> 2
| _ -> tetra (n - 1) + tetra (n - 2) + tetra (n - 3) + tetra (n - 4)
You could economise by devising a function that computes the state for the next iteration on a 4-tuple. Then the sequence generator function Seq.unfold can be used to build a sequence that contains the first element of each state quadruple, an operation that is 'lazy` -- the elements of the sequence are only computed on demand as they are consumed.
let tetranacci (a3, a2, a1, a0) = a2, a1, a0, a3 + a2 + a1 + a0
(0, 1, 1, 2)
|> Seq.unfold (fun (a3, _, _, _ as a30) -> Some(a3, tetranacci a30))
|> Seq.take 10
|> Seq.toList
// val it : int list = [0; 1; 1; 2; 4; 8; 15; 29; 56; 108]
Note that the standard Tetranacci sequence (OEIS A000078) would usually be generated with the start state of (0, 0, 0, 1):
// val it : int list = [0; 0; 0; 1; 1; 2; 4; 8; 15; 29]
kaefer's answer is good, but why stop at linear time? It turns out that you can actually achieve logarithmic time instead, by noting that the recurrence can be expressed as a matrix multiplication:
[T_n+1] [0; 1; 0; 0][T_n]
[T_n+2] = [0; 0; 1; 0][T_n+1]
[T_n+3] [0; 0; 0; 1][T_n+2]
[T_n+4] [1; 1; 1; 1][T_n+3]
But then T_n can be achieved by applying the recurrence n times, which we can see as the first entry of M^n*[T_0; T_1; T_2; T_3] (which is just the upper right entry of M^n), and we can perform the matrix multiplication in O(log n) time by repeated squaring:
type Mat =
| Mat of bigint[][]
static member (*)(Mat arr1, Mat arr2) =
Array.init arr1.Length (fun i -> Array.init arr2.[0].Length (fun j -> Array.sum [| for k in 0 .. arr2.Length - 1 -> arr1.[i].[k]*arr2.[k].[j] |]))
|> Mat
static member Pow(m, n) =
match n with
| 0 ->
let (Mat arr) = m
Array.init arr.Length (fun i -> Array.init arr.Length (fun j -> if i = j then 1I else 0I))
|> Mat
| 1 -> m
| _ ->
let m2 = m ** (n/2)
if n % 2 = 0 then m2 * m2
else m2 * m2 * m
let tetr =
let m = Mat [| [|0I; 1I; 0I; 0I|]
[|0I; 0I; 1I; 0I|]
[|0I; 0I; 0I; 1I|]
[|1I; 1I; 1I; 1I|]|]
fun n ->
let (Mat m') = m ** n
m'.[0].[3]
for i in 0 .. 50 do
printfn "%A" (tetr i)
Here is a tail recursive version, which compiles to mostly loops (and its complexity should be O(n)):
let tetr n =
let rec t acc4 acc3 acc2 acc1 = function
| n when n = 0 -> acc4
| n when n = 1 -> acc3
| n when n = 2 -> acc2
| n when n = 3 -> acc1
| n -> t acc3 acc2 acc1 (acc1 + acc2 + acc3 + acc4) (n - 1)
t 0 1 1 2 n
acc1 corresponds to tetra (n - 1),
acc2 corresponds to tetra (n - 2),
acc3 corresponds to tetra (n - 3),
acc4 corresponds to tetra (n - 4)
Based on the Fibonacci example
I want to find tuple in a set by first two values and return third value of the tuple (or None if found nothing). I woluld like something like that:
type Point = (int * int * int)
type Path = Set<Point>
let f (x:int) (y:int) (p:Path) : int Option =
if Set.exists ((=) (x, y, _z)) p
then Some _z
else None
let p:Path = Set.ofList [ (0, 1, 100); (1, 1, 500); (1, 2, 50); ]
f 1 2 p
But this not works because, apparently, pattern matching does not allowed in expressions. What is the right approach? Thanks.
You can convert the set to list and use List.tryFind
let f (x:int) (y:int) (p:Path) : int Option =
Set.toList p
|> List.tryFind (fun (px, py, _) -> x = px && y = py)
|> Option.map (fun (_, _, pz) -> pz)
Iterating on hvester's answer:
let f (x:int) (y:int) (p:Path) : int Option =
p |> Seq.tryPick (function
| x', y', z' when x = x' && y = y' -> Some z'
| _ -> None)
tryPick essentially does a find and map in one step.
This is a pretty neat solution with fold
let f x y p = Set.fold (function |None -> (fun (x_,y_,z) -> if x=x_ && y=y_ then Some z else None) |f ->fun _ -> f) None p
Is this what you want to do?
let f (x:int) (y:int) (p:Path) : int Option =
match p |> Set.filter (fun (x', y', _) -> x' = x && y' = y) |> Set.toList with
| [(_, _, z)] -> Some z
| [] -> None
| _ -> failwith "More than one point was found!"
Example:
> let p:Path = Set.ofList [ (0, 1, 100); (1, 1, 500); (1, 2, 50); ];;
val p : Path = set [(0, 1, 100); (1, 1, 500); (1, 2, 50)]
> f 1 2 p;;
val it : Option<int> = Some 50
I'm trying to figure out how to get this function to work. I'm very inept with F#, so explanations are appreciated,
let deriv (f:(float->float), dx: float) =
fun f:(float -> float) * dx:float -> x:float -> float
let (f, dx, x) = ((f(x + dx) - f(x))/dx)
Am I using f:(float->float) wrong?
In stead of trying to fix your problems I will explain it from the ground up.
The symbolic derivative is a function that takes a function and returns a new function. However you are trying to calculate the numeric derivative that returns a value given a function, a value, and a delta.
First we will give the function a name: deriv
and it needs three parameters:
1. A function that takes in a float and returns a float: (f : float -> float)
2. A value of where the derivative is to be evaluated: (x0 : float)
3. A delta: (dx : float)
You had two of the three parameters in your example, but were missing x0.
It should also return a float.
So the signature is
deriv (f : (float -> float)) (x0 : float) (dx : float) : float
Now to calculate the numeric derivative.
I won't explain this, but just reference derivative
For this example we'll use a simple function that has derivative, x^2.
Here is the code in F#
// val deriv : f:(float -> float) -> x0:float -> dx:float -> float
let deriv (f : (float -> float)) (x0 : float) (dx : float) : float =
let (x1 : float) = x0 - dx
let (x2 : float) = x0 + dx
let (y1 : float) = f x1
let (y2 : float) = f x2
let (result : float) = (y2 - y1) / (x2 - x1)
result
// val f : x:float -> float
let f x = x**2.0
and a quick test show it works correctly.
// val it : float = 2.0
deriv f 1.0 0.000005
For a more thorough test of a range of values.
Using Visual Studio and NuGet install FSharp.Charting
In F# Interactive
#I "..\packages"
#load "FSharp.Charting.0.90.13\FSharp.Charting.fsx"
open FSharp.Charting
let xs1 = [ for x in (double)(-3.10) .. 0.05 .. 3.10 do yield x]
let ys1 = xs1 |> List.map f
let values1 = List.zip xs1 ys1
Chart.Line(values1)
.WithXAxis(Min=(-4.0), Max=4.0, MajorTickMark = ChartTypes.TickMark(Interval=2.0, IntervalOffset = 1.0, LineWidth = 2))
.WithYAxis(Min=(0.0), Max=10.0, MajorTickMark = ChartTypes.TickMark(Interval=2.0, IntervalOffset = 1.0, LineWidth = 2))
which can also be confirmed using Wolfram Alpha: x^2
A simpler example:
// val d : x:float -> float
let d x = deriv f x 0.00000005
let xs2 = [ for x in (double)(-3.10) .. 0.05 .. 3.10 do yield x]
let ys2 = xs2 |> List.map d
let values2 = List.zip xs2 ys2
Chart.Line(values2)
.WithXAxis(Min=(-4.0), Max=4.0, MajorTickMark = ChartTypes.TickMark(Interval=2.0, IntervalOffset = 1.0, LineWidth = 2))
.WithYAxis(Min=(-6.0), Max=6.0, MajorTickMark = ChartTypes.TickMark(Interval=2.0, IntervalOffset = 1.0, LineWidth = 2))
which can also be confirmed using Wolfram Alpha: d/dx x^2
I'm new to F# and I'm curious if this can still be optimized further. I am not particularly sure if I've done this correctly as well. I'm curious particularly on the last line as it looks really long and hideous.
I've searched over google, but only Roman Numeral to Number solutions only show up, so I'm having a hard time comparing.
type RomanDigit = I | IV | V | IX
let rec romanNumeral number =
let values = [ 9; 5; 4; 1 ]
let capture number values =
values
|> Seq.find ( fun x -> number >= x )
let toRomanDigit x =
match x with
| 9 -> IX
| 5 -> V
| 4 -> IV
| 1 -> I
match number with
| 0 -> []
| int -> Seq.toList ( Seq.concat [ [ toRomanDigit ( capture number values ) ]; romanNumeral ( number - ( capture number values ) ) ] )
Thanks for anyone who can help with this problem.
A slightly shorter way of recursively finding the largest digit representation that can be subtracted from the value (using List.find):
let units =
[1000, "M"
900, "CM"
500, "D"
400, "CD"
100, "C"
90, "XC"
50, "L"
40, "XL"
10, "X"
9, "IX"
5, "V"
4, "IV"
1, "I"]
let rec toRomanNumeral = function
| 0 -> ""
| n ->
let x, s = units |> List.find (fun (x,s) -> x <= n)
s + toRomanNumeral (n-x)
If I had to use a Discriminated Union to represent the roman letters I would not include IV and IX.
type RomanDigit = I|V|X
let numberToRoman n =
let (r, diff) =
if n > 8 then [X], n - 10
elif n > 3 then [V], n - 5
else [], n
if diff < 0 then I::r
else r # (List.replicate diff I)
Then, based in this solution you can go further and extend it to all numbers.
Here's my first attempt, using fold and partial application:
type RomanDigit = I|V|X|L|C|D|M
let numberToRoman n i v x =
let (r, diff) =
if n > 8 then [x], n - 10
elif n > 3 then [v], n - 5
else [], n
if diff < 0 then i::r
else r # (List.replicate diff i)
let allDigits (n:int) =
let (_, f) =
[(I,V); (X,L); (C,D)]
|> List.fold (fun (n, f) (i, v) ->
(n / 10, fun x -> (numberToRoman (n % 10) i v x) # f i)) (n, (fun _ -> []))
f M
Here's a tail-recursive version of #Philip Trelford's answer:
let toRomanNumeral n =
let rec iter acc n =
match n with
| 0 -> acc
| n ->
let x, s = units |> List.find (fun (x, _) -> x <= n)
iter (acc + s) (n-x)
iter "" n