diff --git a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
index 15cfdc6..9e51f8e 100644
--- a/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
+++ b/src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj
@@ -45,6 +45,7 @@ Generates optimized IL code through resumable state machines, and comes with a c
     
     
     
+    
     
     
     
diff --git a/src/FSharp.Control.TaskSeq/TaskEx.Operators.fs b/src/FSharp.Control.TaskSeq/TaskEx.Operators.fs
new file mode 100644
index 0000000..b8cac92
--- /dev/null
+++ b/src/FSharp.Control.TaskSeq/TaskEx.Operators.fs
@@ -0,0 +1,188 @@
+namespace FSharp.Control.Operators
+
+open System.Threading.Tasks
+open System
+
+open FSharp.Control
+
+// "The '&&' should not normally be redefined. Consider using a different operator name.
+// "The '||' should not normally be redefined. Consider using a different operator name.
+#nowarn "86"
+
+[]
+type TaskAndOperator =
+    | TaskAndOperator
+
+    // original. In release builds, this is optimized just like the original '&&' operator and the SCDU disappears
+    static member inline (?<-)(_: TaskAndOperator, leftOp: bool, rightOp: bool) = leftOp && rightOp
+
+    static member (?<-)(TaskAndOperator, leftOp: bool, rightOp: ValueTask) = if leftOp then rightOp else ValueTask.False
+
+    static member (?<-)(TaskAndOperator, leftOp: ValueTask, rightOp: bool) =
+        // while it may be more efficient to evaluate rh-side first, we should honor order of operations!
+        if leftOp.IsCompletedSuccessfully && leftOp.Result then
+            ValueTask.fromResult rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return rightOp else return false
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskAndOperator, leftOp: bool, rightOp: #Task) = if leftOp then ValueTask.ofTask rightOp else ValueTask.False
+
+    static member (?<-)(TaskAndOperator, leftOp: #Task, rightOp: bool) =
+        // while it may be more efficient to evaluate rh-side first, we should honor order of operations!
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.fromResult rightOp
+            else
+                ValueTask.False
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return rightOp else return false
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskAndOperator, leftOp: ValueTask<_>, rightOp: ValueTask<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then rightOp else ValueTask.False
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return! rightOp else return false
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskAndOperator, leftOp: #Task<_>, rightOp: ValueTask<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then rightOp else ValueTask.False
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return! rightOp else return false
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskAndOperator, leftOp: ValueTask<_>, rightOp: #Task<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.ofTask rightOp
+            else
+                ValueTask.False
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return! rightOp else return false
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(_: TaskAndOperator, leftOp: #Task<_>, rightOp: #Task<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.ofTask rightOp
+            else
+                ValueTask.False
+        else
+            task {
+                let! leftOperand = leftOp
+                if not leftOperand then return false else return! rightOp
+            }
+            |> ValueTask.ofTask
+
+
+[]
+type TaskOrOperator =
+    | TaskOrOperator
+
+    // original. In release builds, this is optimized just like the original '||' operator and the SCDU disappears
+    static member inline (?<-)(_, leftOp: bool, rightOp: bool) = leftOp || rightOp
+
+    static member (?<-)(TaskOrOperator, leftOp: bool, rightOp: ValueTask) =
+        // simple
+        if leftOp then ValueTask.True else rightOp
+
+    static member (?<-)(TaskOrOperator, leftOp: ValueTask, rightOp: bool) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.True
+            else
+                ValueTask.fromResult rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                return leftOperand || rightOp
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskOrOperator, leftOp: bool, rightOp: #Task) = if leftOp then ValueTask.True else ValueTask.ofTask rightOp
+
+    static member (?<-)(TaskOrOperator, leftOp: #Task, rightOp: bool) =
+        // while it may be more efficient to evaluate rh-side first, we should honor order of operations!
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.True
+            else
+                ValueTask.fromResult rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                return leftOperand || rightOp
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskOrOperator, leftOp: ValueTask<_>, rightOp: ValueTask<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then ValueTask.True else rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return true else return! rightOp
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskOrOperator, leftOp: #Task<_>, rightOp: ValueTask<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then ValueTask.True else rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return true else return! rightOp
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskOrOperator, leftOp: ValueTask<_>, rightOp: #Task<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.True
+            else
+                ValueTask.ofTask rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return true else return! rightOp
+            }
+            |> ValueTask.ofTask
+
+    static member (?<-)(TaskOrOperator, leftOp: #Task<_>, rightOp: #Task<_>) =
+        if leftOp.IsCompletedSuccessfully then
+            if leftOp.Result then
+                ValueTask.True
+            else
+                ValueTask.ofTask rightOp
+        else
+            task {
+                let! leftOperand = leftOp
+                if leftOperand then return true else return! rightOp
+            }
+            |> ValueTask.ofTask
+
+[]
+module OperatorOverloads =
+
+    /// Binary 'and'. When used as a binary operator, the right-hand operand is evaluated only on demand.
+    let inline (&&) leftOp rightOp : 'T = ((?<-) TaskAndOperator leftOp rightOp) // SCDU will get erased in release builds
+
+    /// Binary 'or'. When used as a binary operator, the right-hand operand is evaluated only on demand.
+    let inline (||) leftOp rightOp : 'T = ((?<-) TaskOrOperator leftOp rightOp) // SCDU will get erased in release builds
diff --git a/src/FSharp.Control.TaskSeq/Utils.fs b/src/FSharp.Control.TaskSeq/Utils.fs
index c02bab3..687e4c0 100644
--- a/src/FSharp.Control.TaskSeq/Utils.fs
+++ b/src/FSharp.Control.TaskSeq/Utils.fs
@@ -42,6 +42,8 @@ module ValueTask =
 
 
 module Task =
+    let False = Task.FromResult false
+    let True = Task.FromResult true
     let inline fromResult (value: 'U) : Task<'U> = Task.FromResult value
     let inline ofAsync (async: Async<'T>) = task { return! async }
     let inline ofTask (task': Task) = task { do! task' }
diff --git a/src/FSharp.Control.TaskSeq/Utils.fsi b/src/FSharp.Control.TaskSeq/Utils.fsi
index d34a1e5..74a3ba2 100644
--- a/src/FSharp.Control.TaskSeq/Utils.fsi
+++ b/src/FSharp.Control.TaskSeq/Utils.fsi
@@ -49,6 +49,11 @@ module ValueTask =
     val inline ignore: vtask: ValueTask<'T> -> ValueTask
 
 module Task =
+    /// A successfully completed Task of boolean that has the value false.
+    val False: Task
+
+    /// A successfully completed Task of boolean that has the value true.
+    val True: Task
 
     /// Convert an Async<'T> into a Task<'T>
     val inline ofAsync: async: Async<'T> -> Task<'T>