diff --git a/Tasks/Continuation/Continuation.Tests/Continuation.Tests.fsproj b/Tasks/Continuation/Continuation.Tests/Continuation.Tests.fsproj new file mode 100644 index 0000000..310607d --- /dev/null +++ b/Tasks/Continuation/Continuation.Tests/Continuation.Tests.fsproj @@ -0,0 +1,27 @@ + + + net9.0 + latest + false + false + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tasks/Continuation/Continuation.Tests/EvenNumbersTests.fs b/Tasks/Continuation/Continuation.Tests/EvenNumbersTests.fs new file mode 100644 index 0000000..9852775 --- /dev/null +++ b/Tasks/Continuation/Continuation.Tests/EvenNumbersTests.fs @@ -0,0 +1,28 @@ +module EvenNumbersTests + +open NUnit.Framework +open FsUnit +open FsCheck +open FsCheck.NUnit + +open EvenNumbers + +[] +let testEvenNumbers_Map () = + countEvenNumbers_Map [] |> should equal 0 + countEvenNumbers_Map [1; 5; -3; 5; 77; 9] |> should equal 0 + countEvenNumbers_Map [4; 6; 8; 8] |> should equal 4 + countEvenNumbers_Map [0; 0; 1; 2; 3] |> should equal 3 + countEvenNumbers_Map [56592; -321321; 898934; 90901; -137] |> should equal 2 + countEvenNumbers_Map [2147483647] |> should equal 0 + +[] +let areEquivalent_MapAndFilter (list: list) = + countEvenNumbers_Map list = countEvenNumbers_Filter list + +[] +let areEquivalent_FilterAndFold (list: list) = + countEvenNumbers_Filter list = countEvenNumbers_Fold list + +Check.QuickThrowOnFailure areEquivalent_MapAndFilter +Check.QuickThrowOnFailure areEquivalent_FilterAndFold diff --git a/Tasks/Continuation/Continuation.Tests/ParseTreeTests.fs b/Tasks/Continuation/Continuation.Tests/ParseTreeTests.fs new file mode 100644 index 0000000..f302dd3 --- /dev/null +++ b/Tasks/Continuation/Continuation.Tests/ParseTreeTests.fs @@ -0,0 +1,40 @@ +module ParseTreeTests + +open NUnit.Framework +open FsUnit +open System + +open ParseTree + +[] +let testEvaluate () = + let ``1 + 1`` = Operator (Sum, Const 1, Const 1) + let ``25 - 100`` = Operator (Difference, Const 25, Const 100) + let ``8 * 5`` = Operator (Product, Const 8, Const 5) + let ``8 * 5 + 25 - 100`` = Operator (Sum, ``8 * 5``, ``25 - 100``) + let ``14 / (1 + 1)`` = Operator (Ratio, Const 14, ``1 + 1``) + let ``14 / (1 + 1) - 9`` = Operator (Difference, ``14 / (1 + 1)``, Const 9) + let ``3 * (14 / (1 + 1) - 9)`` = Operator (Product, Const 3, ``14 / (1 + 1) - 9``) + let ``321 * 0`` = Operator (Product, Const 321, Const 0) + let ``0 / 0`` = Operator (Ratio, Const 0, Const 0) + let ``(1 + 1) / (321 * 0)`` = Operator (Ratio, ``1 + 1``, ``321 * 0``) + + evaluate (Const 0) |> should equal 0 + evaluate ``1 + 1`` |> should equal 2 + evaluate ``25 - 100`` |> should equal -75 + evaluate ``8 * 5`` |> should equal 40 + evaluate ``8 * 5 + 25 - 100`` |> should equal -35 + evaluate ``14 / (1 + 1)`` |> should equal 7 + evaluate ``14 / (1 + 1) - 9`` |> should equal -2 + evaluate ``3 * (14 / (1 + 1) - 9)`` |> should equal -6 + evaluate ``321 * 0`` |> should equal 0 + (fun () -> evaluate ``0 / 0`` |> ignore) |> should throw typeof + (fun () -> evaluate ``(1 + 1) / (321 * 0)`` |> ignore) |> should throw typeof + +[] +let testEvaluateWithLargeExpression () = + let treeDepth = 1000000 + { 1 .. treeDepth } + |> Seq.fold (fun node _ -> Operator (Sum, node, Const 1)) (Const 1) + |> evaluate + |> should equal (treeDepth + 1) diff --git a/Tasks/Continuation/Continuation.Tests/PrimesTests.fs b/Tasks/Continuation/Continuation.Tests/PrimesTests.fs new file mode 100644 index 0000000..50d2697 --- /dev/null +++ b/Tasks/Continuation/Continuation.Tests/PrimesTests.fs @@ -0,0 +1,28 @@ +module PrimesTests + +open NUnit.Framework +open FsUnit + +open Primes + +[] +let testIsPrime () = + isPrime 0 |> should be False + isPrime 1 |> should be False + isPrime 2 |> should be True + isPrime 3 |> should be True + isPrime 73 |> should be True + isPrime 32132 |> should be False + isPrime -9091 |> should be False + isPrime 115249 |> should be True + +[] +let testPrimes () = + let primes = primes () + primes |> Seq.take 10 |> should equal (seq { 2; 3; 5; 7; 11; 13; 17; 19; 23; 29 }) + primes |> Seq.item 41 |> should equal 181 + primes |> Seq.item 978 |> should equal 7717 + let primes = Seq.take 100000 primes + primes |> should be ascending + primes |> should be unique + primes |> Seq.filter isPrime |> should equal primes diff --git a/Tasks/Continuation/Continuation.Tests/Program.fs b/Tasks/Continuation/Continuation.Tests/Program.fs new file mode 100644 index 0000000..96b133f --- /dev/null +++ b/Tasks/Continuation/Continuation.Tests/Program.fs @@ -0,0 +1,4 @@ +module Program + +[] +let main _ = 0 diff --git a/Tasks/Continuation/Continuation.Tests/TreeMapTests.fs b/Tasks/Continuation/Continuation.Tests/TreeMapTests.fs new file mode 100644 index 0000000..72bf060 --- /dev/null +++ b/Tasks/Continuation/Continuation.Tests/TreeMapTests.fs @@ -0,0 +1,42 @@ +module TreeMapTests + +open NUnit.Framework +open FsUnit + +open TreeMap + +[] +let testTreeMap () = + let strTree = + Node ("abc", + Node ("", Empty, Node ("21321", Empty, Empty)), + Node ("ololo332", Empty, Empty)) + let lenTree = + Node (3, + Node (0, Empty, Node (5, Empty, Empty)), + Node (8, Empty, Empty)) + let intTree = + Node (1, Empty, Node (2, Empty, Node (3, Empty, Node (4, Empty, Empty)))) + let squaresTree = + Node (1, Empty, Node (4, Empty, Node (9, Empty, Node (16, Empty, Empty)))) + + map (( * ) 5) Empty |> should equal Tree.Empty + map (( = ) 0) (Node (0, Empty, Empty)) |> should equal (Node (true, Empty, Empty)) + map sqrt (Node (9.0, Empty, Empty)) |> should equal (Node (3.0, Empty, Empty)) + map String.length strTree |> should equal lenTree + map (fun x -> x * x) intTree |> should equal squaresTree + +[] +let testMapWithLargeTree () = + let treeDepth = 1000000 + let sourceTree = + { 1 .. treeDepth } + |> Seq.fold (fun node _ -> Node (1, node, Empty)) Empty + let resultTree = + { 1 .. treeDepth } + |> Seq.fold (fun node _ -> Node (8, node, Empty)) Empty + + sourceTree + |> map (( + ) 7) + |> areEqual resultTree + |> should be True diff --git a/Tasks/Continuation/Continuation.sln b/Tasks/Continuation/Continuation.sln new file mode 100644 index 0000000..9e704d1 --- /dev/null +++ b/Tasks/Continuation/Continuation.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Continuation", "Continuation\Continuation.fsproj", "{F1533830-EECE-4FFF-AA1F-640C75003521}" +EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Continuation.Tests", "Continuation.Tests\Continuation.Tests.fsproj", "{06E91877-A8A4-4068-A038-566B457A95E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F1533830-EECE-4FFF-AA1F-640C75003521}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1533830-EECE-4FFF-AA1F-640C75003521}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1533830-EECE-4FFF-AA1F-640C75003521}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1533830-EECE-4FFF-AA1F-640C75003521}.Release|Any CPU.Build.0 = Release|Any CPU + {06E91877-A8A4-4068-A038-566B457A95E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {06E91877-A8A4-4068-A038-566B457A95E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {06E91877-A8A4-4068-A038-566B457A95E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {06E91877-A8A4-4068-A038-566B457A95E2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Tasks/Continuation/Continuation/Continuation.fsproj b/Tasks/Continuation/Continuation/Continuation.fsproj new file mode 100644 index 0000000..1078db1 --- /dev/null +++ b/Tasks/Continuation/Continuation/Continuation.fsproj @@ -0,0 +1,16 @@ + + + + net9.0 + true + true + + + + + + + + + + diff --git a/Tasks/Continuation/Continuation/EvenNumbers.fs b/Tasks/Continuation/Continuation/EvenNumbers.fs new file mode 100644 index 0000000..977e0f9 --- /dev/null +++ b/Tasks/Continuation/Continuation/EvenNumbers.fs @@ -0,0 +1,14 @@ +module EvenNumbers + +let ( %% ) x y = + let rem = x % y + if rem >= 0 then rem else rem + y + +let countEvenNumbers_Map: list -> int = + Seq.map (fun x -> (x + 1) %% 2) >> Seq.sum + +let countEvenNumbers_Filter: list -> int = + Seq.filter (fun x -> x % 2 = 0) >> Seq.length + +let countEvenNumbers_Fold: list -> int = + Seq.fold (fun acc x -> acc + (x + 1) %% 2) 0 diff --git a/Tasks/Continuation/Continuation/ParseTree.fs b/Tasks/Continuation/Continuation/ParseTree.fs new file mode 100644 index 0000000..035330d --- /dev/null +++ b/Tasks/Continuation/Continuation/ParseTree.fs @@ -0,0 +1,31 @@ +module ParseTree + +type Operation = + | Sum + | Difference + | Product + | Ratio + +type Expression = + | Const of int + | Operator of Operation * Expression * Expression + +let operation op = + match op with + | Sum -> ( + ) + | Difference -> ( - ) + | Product -> ( * ) + | Ratio -> ( / ) + +[] +let rec evaluateCPS expr cont = + match expr with + | Const x -> cont x + | Operator (op, left, right) -> + evaluateCPS left (fun leftValue -> + evaluateCPS right (fun rightValue -> + operation op leftValue rightValue |> cont + ) + ) + +let evaluate expr = evaluateCPS expr id diff --git a/Tasks/Continuation/Continuation/Primes.fs b/Tasks/Continuation/Continuation/Primes.fs new file mode 100644 index 0000000..b5145ae --- /dev/null +++ b/Tasks/Continuation/Continuation/Primes.fs @@ -0,0 +1,13 @@ +module Primes + +let isPrime n = + if n >= 2 then + { 2 .. int (sqrt (float n)) } + |> Seq.exists (fun x -> n % x = 0) + |> not + else false + +let primes () = + ( + ) 2 + |> Seq.initInfinite + |> Seq.filter isPrime diff --git a/Tasks/Continuation/Continuation/TreeMap.fs b/Tasks/Continuation/Continuation/TreeMap.fs new file mode 100644 index 0000000..d2c1e23 --- /dev/null +++ b/Tasks/Continuation/Continuation/TreeMap.fs @@ -0,0 +1,33 @@ +module TreeMap + +type Tree<'a> = + | Empty + | Node of 'a * Tree<'a> * Tree<'a> + +[] +let rec private mapCPS mapping tree cont = + match tree with + | Empty -> cont Empty + | Node (value, left, right) -> + mapCPS mapping left (fun mappedLeft -> + mapCPS mapping right (fun mappedRight -> + Node (mapping value, mappedLeft, mappedRight) |> cont + ) + ) + +let map mapping tree = mapCPS mapping tree id + +[] +let rec private areEqualCPS tree1 tree2 cont = + match tree1, tree2 with + | Empty, Empty -> cont true + | Empty, Node _ | Node _, Empty -> cont false + | Node (val1, _, _), Node (val2, _, _) when val1 <> val2 -> cont false + | Node (_, left1, right1), Node (_, left2, right2) -> + areEqualCPS left1 left2 (fun leftAreEqual -> + areEqualCPS right1 right2 (fun rightAreEqual -> + leftAreEqual && rightAreEqual |> cont + ) + ) + +let areEqual tree1 tree2 = areEqualCPS tree1 tree2 id