diff --git a/F#/Lazy.Test/Lazy.Test.fsproj b/F#/Lazy.Test/Lazy.Test.fsproj
new file mode 100644
index 0000000..4b4c995
--- /dev/null
+++ b/F#/Lazy.Test/Lazy.Test.fsproj
@@ -0,0 +1,29 @@
+
+
+
+ net8.0
+
+ false
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/F#/Lazy.Test/LazyTest.fs b/F#/Lazy.Test/LazyTest.fs
new file mode 100644
index 0000000..a744f1e
--- /dev/null
+++ b/F#/Lazy.Test/LazyTest.fs
@@ -0,0 +1,67 @@
+module Lazy.Test
+
+open NUnit.Framework
+open FsUnit
+
+type Counter () =
+ let mutable callCounter = 0
+ member this.Increment () =
+ System.Threading.Interlocked.Increment(&callCounter)
+ member this.Counter = callCounter
+
+let lazyImplementations =
+ [
+ (fun func -> S.Lazy func :> ILazy.ILazy)
+ (fun func -> M.Lazy func)
+ (fun func -> LF.Lazy func)
+ ] |> List.map (fun x -> TestCaseData(x))
+
+[]
+[]
+let getTest (genLazy) =
+ let l : ILazy.ILazy = genLazy (fun () -> 1)
+ l.Get() |> should equal 1
+
+[]
+let singleThreadCountTest () =
+ let counter = Counter()
+ let l : ILazy.ILazy = S.Lazy(counter.Increment)
+ l.Get() |> ignore
+ l.Get() |> ignore
+ l.Get() |> ignore
+ counter.Counter |> should equal 1
+
+[]
+let simpleMultiThrCountTest () =
+ let counter = Counter()
+ let l : ILazy.ILazy = M.Lazy(counter.Increment)
+ l.Get() |> ignore
+ l.Get() |> ignore
+ l.Get() |> ignore
+ counter.Counter |> should equal 1
+
+[]
+let complexMultiThrCountTest () =
+ let counter = Counter()
+ let l : ILazy.ILazy = M.Lazy(counter.Increment)
+ let getTask = task { return l.Get() }
+ let results = (fun _ -> getTask |> Async.AwaitTask) |> Seq.initInfinite |> Seq.take 10 |> Async.Parallel |> Async.RunSynchronously
+ counter.Counter |> should equal 1
+ Seq.iter (fun x -> (x = (Seq.last results)) |> should equal true) results
+
+[]
+let simpleLockFreeTest () =
+ let counter = Counter()
+ let l : ILazy.ILazy = LF.Lazy(counter.Increment)
+ l.Get() |> ignore
+ l.Get() |> ignore
+ l.Get() |> ignore
+ counter.Counter |> should equal 1
+
+[]
+let complexLockFreeTest () =
+ let counter = Counter()
+ let l : ILazy.ILazy = LF.Lazy(counter.Increment)
+ let getTask = task { return l.Get() }
+ let results = (fun _ -> getTask |> Async.AwaitTask) |> Seq.initInfinite |> Seq.take 10 |> Async.Parallel |> Async.RunSynchronously
+ Seq.iter (fun x -> (x = (Seq.last results)) |> should equal true) results
diff --git a/F#/Lazy/ILazy.fs b/F#/Lazy/ILazy.fs
new file mode 100644
index 0000000..ed49d25
--- /dev/null
+++ b/F#/Lazy/ILazy.fs
@@ -0,0 +1,12 @@
+module Lazy.ILazy
+
+///
+/// Interface for lazy function calculation
+///
+/// Function return value
+type ILazy<'a> =
+ ///
+ /// Lazily calculates given function
+ ///
+ /// Function result
+ abstract member Get: unit -> 'a
diff --git a/F#/Lazy/Lazy.fsproj b/F#/Lazy/Lazy.fsproj
new file mode 100644
index 0000000..03d5967
--- /dev/null
+++ b/F#/Lazy/Lazy.fsproj
@@ -0,0 +1,15 @@
+
+
+
+ net8.0
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/F#/Lazy/LockFreeLazy.fs b/F#/Lazy/LockFreeLazy.fs
new file mode 100644
index 0000000..821e2c6
--- /dev/null
+++ b/F#/Lazy/LockFreeLazy.fs
@@ -0,0 +1,14 @@
+module Lazy.LF
+
+///
+/// Lock free multi threaded implementation of iLazy interface
+///
+/// Result type
+type Lazy<'a>(func) =
+ let mutable value : Option<'a> = None
+ interface ILazy.ILazy<'a> with
+ member this.Get() =
+ if value.IsNone then
+ let localValue = func()
+ System.Threading.Interlocked.CompareExchange(&value, Some(localValue), None) |> ignore
+ value.Value
diff --git a/F#/Lazy/MultiThreadedLazy.fs b/F#/Lazy/MultiThreadedLazy.fs
new file mode 100644
index 0000000..5065ccf
--- /dev/null
+++ b/F#/Lazy/MultiThreadedLazy.fs
@@ -0,0 +1,17 @@
+module Lazy.M
+
+///
+/// Multi threaded implementation of iLazy interface
+///
+/// Result type
+type Lazy<'a>(func) =
+ let mutable value : Option<'a> = None
+ let valueLock = obj
+ interface ILazy.ILazy<'a> with
+ member this.Get() =
+ if value.IsNone then
+ lock valueLock (fun () ->
+ if value.IsNone then
+ value <- Some(func())
+ )
+ value.Value
diff --git a/F#/Lazy/SingleThreadedLazy.fs b/F#/Lazy/SingleThreadedLazy.fs
new file mode 100644
index 0000000..2cc1f15
--- /dev/null
+++ b/F#/Lazy/SingleThreadedLazy.fs
@@ -0,0 +1,13 @@
+module Lazy.S
+
+///
+/// Single threaded implementation of iLazy interface
+///
+/// Result type
+type Lazy<'a>(f) =
+ let mutable value : Option<'a> = None
+ interface ILazy.ILazy<'a> with
+ member this.Get() =
+ if value.IsNone then
+ value <- Some(f())
+ value.Value
diff --git a/F#/forSpbu.sln b/F#/forSpbu.sln
index 9d54d03..b38709a 100644
--- a/F#/forSpbu.sln
+++ b/F#/forSpbu.sln
@@ -21,6 +21,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "07.03", "07.03", "{5CA9053B
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Homework1", "Homework1\Homework1.fsproj", "{04B15EE4-079A-42ED-ACC8-E2DCD25281C6}"
EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Lazy", "Lazy\Lazy.fsproj", "{31761996-9105-4FCD-A2BE-87F64952A72A}"
+EndProject
+Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Lazy.Test", "Lazy.Test\Lazy.Test.fsproj", "{F290B1F9-5753-4585-881D-25641368A803}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,6 +62,14 @@ Global
{89A935E8-B5F3-435D-ACC3-A99DD7C66178}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89A935E8-B5F3-435D-ACC3-A99DD7C66178}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89A935E8-B5F3-435D-ACC3-A99DD7C66178}.Release|Any CPU.Build.0 = Release|Any CPU
+ {31761996-9105-4FCD-A2BE-87F64952A72A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {31761996-9105-4FCD-A2BE-87F64952A72A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {31761996-9105-4FCD-A2BE-87F64952A72A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {31761996-9105-4FCD-A2BE-87F64952A72A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F290B1F9-5753-4585-881D-25641368A803}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F290B1F9-5753-4585-881D-25641368A803}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F290B1F9-5753-4585-881D-25641368A803}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F290B1F9-5753-4585-881D-25641368A803}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7937CDA8-8285-4E23-AD1A-FC0F04FEEFE6} = {91E3BDA2-0836-46C2-95F0-02513FD7F13F}