Nested loop and functional programming - f#

Please consider a C program that, given x, will return y and z such that y + z * 2 = x, for the smallest possible y. Roughly, I could create a nested loop:
for(y = 0; y < x; ++ y){
for(z = 0; z < x; ++z){
if(y + 2 * z == x){
printf("%d + 2 * %d = %d", y, z, x);
}
}
}
How could I translate this kind of nested loop in the functional way? Is it feasible? Is it reasonable or am I just misjudging the approach? My best attempt so far:
let foo x =
let rec aux (y, z, q) =
match (y + z * 2) with
r when r = q -> (y, z)
|_ -> aux(y + 1, z + 1, q) //How to check different values of z
aux(0, 0, x) //for each value of y?
It will not work, since it will just increment both y and z. How can I check different values of z, for every value of y?

You have to add those checks in the match.
See here what your code is missing:
let foo x =
let rec aux (y, z, q) =
match (y + z * 2) with
| r when r = q -> (y, z)
| _ when y = q -> failwith "not found !"
| _ when z = q -> aux (y + 1, 0, q)
| _ -> aux (y, z + 1, q)
aux (0, 0, x)
And here's a different approach, equally functional but without recursion:
let foo2 x =
let s =
{0 .. x} |> Seq.collect (fun y ->
{0 .. x} |> Seq.collect (fun z ->
seq [y, z]))
Seq.find (fun (y, z) -> y + z * 2 = x) s
which in F# can be written using seq expressions:
let foo3 x =
let s = seq {
for y in {0 .. x} do
for z in {0 .. x} do
yield (y, z)}
Seq.find (fun (y, z) -> y + z * 2 = x) s
and it resembles your original C program.

Related

How to sum adjacent numbers of same sign using List.fold in F#

Let's say I have a list in F# like this: [5,-2, -6, 7, -2, 2, 14, 2]
I want to write a function that will use List.fold to return a new list such as [5, -8, 7, -2, 18]
My template looks like this:
let sumAdjacentOfSameSign (lst :int list) : int list =
let f x y =
if x.Length = 0 then
[y]
elif System.Math.Sign(x) = System.Math.Sign(y) then ...
else y :: x
List.fold f [] lst
I need to fill in the ... part but can't quite say how.
Making the fewest changes to your code, I would do this:
let sumAdjacentOfSameSign (lst :int list) : int list =
let f (x : int list) (y : int) =
if x.Length = 0 then
[y]
elif System.Math.Sign(x.Head) = System.Math.Sign(y) then
(x.Head + y) :: x.Tail
else y :: x
List.fold f [] lst
|> List.rev // note that you have to reverse the resulting list
But I would suggest simplifying f to:
let f (x : int list) (y : int) =
match x with
| head :: tail when
System.Math.Sign(head) = System.Math.Sign(y) ->
(head + y) :: tail
| _ -> y :: x

F# Matching results of recursive calls using higher order functions

Given a simple function, where we do pattern matching on the result of a recursive call, such as:
let rec sumProd = function
| [] -> (0,1)
| x::rest -> let (rSum,rProd) = sumProd rest
(x + rSum,x * rProd)
sumProd [2;5] //Expected (7, 10)
How would I go about changing it into something using higher order functions, e.g. foldBack?
let sumProdHigherOrder lst =
List.foldBack (fun x acc -> (acc + x, acc * x)) lst (0,0)
The above seemed almost like the way to do it, but calling it gives the error: The type 'int' does not match the type 'int * int'
sumProdHigherOrder [2;5] //Expected (7, 10)
What am I missing?
Your missing the tuple functions fst and snd:
List.foldBack (fun x acc -> (fst acc + x, snd acc * x)) [2;5] (0,1)
// val it : int * int = (7, 10)
Or even better, decomposing the tuple at the lambda. I see you just found it:
List.foldBack (fun x (s, m) -> (s + x, m * x)) [2;5] (0,1)
Also note that since the operations are commutative you can do a straight fold:
List.fold (fun (s, m) x -> (s + x, m * x)) (0,1) [2;5]
It will be more efficient.
Right! Of course it shouldn't be the same accumulator that gets passed through the list. After staring intensely at the code for some minutes, I figured it out:
let sumProdHigherOrder lst =
List.foldBack (fun x (acc,acc') -> (acc + x, acc' * x)) lst (0,1)

Get element from set of tuples in F#

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

How do you sum up and average a Sequence?

Say I have a coordinate (x, y) and its neighbors in a sequences of sequence (-1, 1)(0, 1)(1, 1)(-1, 0)(0, 0)(1, 0)(-1, -1)(0, -1)(1, -1)
let n = [1 .. -1 .. -1]
|> Seq.collect (fun j -> [-1 .. 1] |> Seq.map(fun i -> [i, j]))
n |> Seq.iter(printf "%A")
I'm trying to add x and y to each element in the sequence respectively
Then get Color p = GetPixel(x+i, y+j) for every element in sequence, sum up and average out their R, G, B for (x,y)
So we have 9 Red, 9 Green, 9 Blue to Ave(Red), Ave(Blue), Ave(Green)
let offsets = seq { for i in -1 .. 1 do for j in -1 .. 1 do yield (i, j) }
let neighbourhood (x, y) = Seq.map (fun (i, j) -> (x + i, y + j)) offsets
let avgColours (cs : System.Drawing.Color seq) =
let ((r, g, b), c) = cs |> Seq.fold (fun ((r, g, b), c) col -> ((r + int col.R, g + int col.G, b + int col.B), c + 1)) ((0, 0, 0), 0)
System.Drawing.Color.FromArgb(r / c, g / c, b / c)
let avgNeighbours p = p |> neighbourhood |> Seq.map (fun (x, y) -> GetPixel(x, y)) |> avgColours
Something like this?
let f x y =
let n = [1 .. -1 .. -1] |> Seq.collect (fun j -> [-1 .. 1] |> Seq.map(fun i -> (i, j)))
n |> Seq.map (fun (i,j) -> x+i,y+j)
|> Seq.map bitmapobject.GetPixel
|> Seq.map (fun c -> float c.R, float c.G, float c.B)
|> Seq.fold (fun (R,G,B) (r,g,b) -> (R+r, G+g, B+b)) (0.0, 0.0, 0.0)
|> (fun (r,g,b) -> (r/9.0, g/9.0, b/9.0))

F# Using recursive lists

My code (below) falls over with a stack overflow exception. Im assuming F# isnt like haskell and dosent play well with recursive lists. Whats the correct way of dealing with recursive lists like this in F# ? Should i pass it an int so it has a determined size?
let rec collatz num =
match num with
|x when x % 2 = 0 ->num :: collatz (x/2)
|x -> num :: collatz ((x * 3) + 1)
let smallList = collatz(4) |> Seq.take(4)
For an infinite list like this, you want to return a sequence. Sequences are lazy; lists are not.
let rec collatz num =
seq {
yield num
match num with
| x when x % 2 = 0 -> yield! collatz (x/2)
| x -> yield! collatz ((x * 3) + 1)
}
let smallList =
collatz 4
|> Seq.take 4
|> Seq.toList //[4; 2; 1; 4]
let collatz num =
let next x = if x % 2 = 0 then x / 2 else x * 3 + 1
(num, next num)
|>Seq.unfold (fun (n, x) -> Some (n, (x, next x)))

Resources