1/**
2 * Works with TypeScript `boolean` values.
3 *
4 * This module exposes the native `Boolean` constructor together with helpers
5 * for checking values, choosing between lazy branches, combining booleans with
6 * logical operations, checking collections with `every` or `some`, ordering
7 * booleans, and reducing boolean values.
8 *
9 * @since 2.0.0
10 */
11import * as Equ from "./Equivalence.ts"
12import type { LazyArg } from "./Function.ts"
13import { dual } from "./Function.ts"
14import * as order from "./Order.ts"
15import * as predicate from "./Predicate.ts"
16import * as Reducer from "./Reducer.ts"
17
18/**
19 * Exposes the global boolean constructor for JavaScript truthiness
20 * coercion.
21 *
22 * **When to use**
23 *
24 * Use to access native JavaScript truthiness coercion from the Effect module
25 * namespace.
26 *
27 * **Gotchas**
28 *
29 * This follows native truthiness rules. For example, non-empty strings such as
30 * `"false"` coerce to `true`.
31 *
32 * **Example** (Coercing values to booleans)
33 *
34 * ```ts import.meta.vitest
35 * import { Boolean } from "effect"
36 *
37 * Boolean.Boolean(1) // => true
38 * Boolean.Boolean("false") // => true
39 * Boolean.Boolean(0) // => false
40 * ```
41 *
42 * @category constructors
43 * @since 4.0.0
44 */
45export const Boolean = globalThis.Boolean
46
47/**
48 * Checks whether a value is a `boolean`.
49 *
50 * **When to use**
51 *
52 * Use to validate unknown input and narrow it to `boolean`.
53 *
54 * **Example** (Checking for booleans)
55 *
56 * ```ts import.meta.vitest
57 * import { Boolean } from "effect"
58 *
59 * Boolean.isBoolean(true) // => true
60 * Boolean.isBoolean("true") // => false
61 * ```
62 *
63 * @category guards
64 * @since 2.0.0
65 */
66export const isBoolean: (input: unknown) => input is boolean = predicate.isBoolean
67
68/**
69 * Chooses between two lazy branches based on a boolean value.
70 *
71 * **When to use**
72 *
73 * Use to choose between two lazy branches based on a boolean value.
74 *
75 * **Example** (Pattern matching on booleans)
76 *
77 * ```ts import.meta.vitest
78 * import { Boolean } from "effect"
79 *
80 * Boolean.match(true, {
81 * onFalse: () => "It's false!",
82 * onTrue: () => "It's true!"
83 * }) // => "It's true!"
84 * ```
85 *
86 * @category pattern matching
87 * @since 2.0.0
88 */
89export const match: {
90 <A, B = A>(options: {
91 readonly onFalse: LazyArg<A>
92 readonly onTrue: LazyArg<B>
93 }): (value: boolean) => A | B
94 <A, B>(value: boolean, options: {
95 readonly onFalse: LazyArg<A>
96 readonly onTrue: LazyArg<B>
97 }): A | B
98} = dual(2, <A, B>(value: boolean, options: {
99 readonly onFalse: LazyArg<A>
100 readonly onTrue: LazyArg<B>
101}): A | B => value ? options.onTrue() : options.onFalse())
102
103/**
104 * Provides an `Order` instance for `boolean` that allows comparing and sorting boolean values.
105 * In this ordering, `false` is considered less than `true`.
106 *
107 * **When to use**
108 *
109 * Use when you need to sort or compare boolean values through APIs that accept
110 * an ordering instance where `false` comes before `true`.
111 *
112 * **Example** (Comparing booleans)
113 *
114 * ```ts import.meta.vitest
115 * import { Boolean } from "effect"
116 *
117 * Boolean.Order(false, true) // => -1
118 * Boolean.Order(true, false) // => 1
119 * Boolean.Order(true, true) // => 0
120 * ```
121 *
122 * @category instances
123 * @since 2.0.0
124 */
125export const Order: order.Order<boolean> = order.Boolean
126
127/**
128 * Equivalence instance for booleans using strict equality (`===`).
129 *
130 * **When to use**
131 *
132 * Use when checking boolean equality through APIs that accept an equivalence
133 * relation.
134 *
135 * **Example** (Comparing booleans for equivalence)
136 *
137 * ```ts import.meta.vitest
138 * import { Boolean } from "effect"
139 *
140 * Boolean.Equivalence(true, true) // => true
141 * Boolean.Equivalence(true, false) // => false
142 * ```
143 *
144 * @category instances
145 * @since 2.0.0
146 */
147export const Equivalence: Equ.Equivalence<boolean> = Equ.Boolean
148
149/**
150 * Negates the given boolean: `!self`
151 *
152 * **When to use**
153 *
154 * Use to invert a boolean value.
155 *
156 * **Example** (Negating booleans)
157 *
158 * ```ts import.meta.vitest
159 * import { Boolean } from "effect"
160 *
161 * Boolean.not(true) // => false
162 * Boolean.not(false) // => true
163 * ```
164 *
165 * @category combinators
166 * @since 2.0.0
167 */
168export const not = (self: boolean): boolean => !self
169
170/**
171 * Combines two booleans using logical AND: `self && that`.
172 *
173 * **When to use**
174 *
175 * Use to require both boolean operands to be `true`.
176 *
177 * **Details**
178 *
179 * Supports both data-first and data-last forms.
180 *
181 * **Example** (Combining booleans with AND)
182 *
183 * ```ts import.meta.vitest
184 * import { Boolean } from "effect"
185 *
186 * Boolean.and(true, true) // => true
187 * Boolean.and(true, false) // => false
188 * Boolean.and(false, true) // => false
189 * Boolean.and(false, false) // => false
190 * ```
191 *
192 * @category combinators
193 * @since 2.0.0
194 */
195export const and: {
196 (that: boolean): (self: boolean) => boolean
197 (self: boolean, that: boolean): boolean
198} = dual(2, (self: boolean, that: boolean): boolean => self && that)
199
200/**
201 * Combines two booleans using NAND: `!(self && that)`.
202 *
203 * **When to use**
204 *
205 * Use to negate a logical AND result.
206 *
207 * **Example** (Combining booleans with NAND)
208 *
209 * ```ts import.meta.vitest
210 * import { Boolean } from "effect"
211 *
212 * Boolean.nand(true, true) // => false
213 * Boolean.nand(true, false) // => true
214 * Boolean.nand(false, true) // => true
215 * Boolean.nand(false, false) // => true
216 * ```
217 *
218 * @category combinators
219 * @since 2.0.0
220 */
221export const nand: {
222 (that: boolean): (self: boolean) => boolean
223 (self: boolean, that: boolean): boolean
224} = dual(2, (self: boolean, that: boolean): boolean => !(self && that))
225
226/**
227 * Combines two booleans using OR: `self || that`.
228 *
229 * **When to use**
230 *
231 * Use to accept when either boolean operand is `true`.
232 *
233 * **Example** (Combining booleans with OR)
234 *
235 * ```ts import.meta.vitest
236 * import { Boolean } from "effect"
237 *
238 * Boolean.or(true, true) // => true
239 * Boolean.or(true, false) // => true
240 * Boolean.or(false, true) // => true
241 * Boolean.or(false, false) // => false
242 * ```
243 *
244 * @category combinators
245 * @since 2.0.0
246 */
247export const or: {
248 (that: boolean): (self: boolean) => boolean
249 (self: boolean, that: boolean): boolean
250} = dual(2, (self: boolean, that: boolean): boolean => self || that)
251
252/**
253 * Combines two booleans using NOR: `!(self || that)`.
254 *
255 * **When to use**
256 *
257 * Use to accept only when both boolean operands are `false`.
258 *
259 * **Example** (Combining booleans with NOR)
260 *
261 * ```ts import.meta.vitest
262 * import { Boolean } from "effect"
263 *
264 * Boolean.nor(true, true) // => false
265 * Boolean.nor(true, false) // => false
266 * Boolean.nor(false, true) // => false
267 * Boolean.nor(false, false) // => true
268 * ```
269 *
270 * @category combinators
271 * @since 2.0.0
272 */
273export const nor: {
274 (that: boolean): (self: boolean) => boolean
275 (self: boolean, that: boolean): boolean
276} = dual(2, (self: boolean, that: boolean): boolean => !(self || that))
277
278/**
279 * Combines two booleans using XOR: `(!self && that) || (self && !that)`.
280 *
281 * **When to use**
282 *
283 * Use to accept when exactly one boolean operand is `true`.
284 *
285 * **Example** (Combining booleans with XOR)
286 *
287 * ```ts import.meta.vitest
288 * import { Boolean } from "effect"
289 *
290 * Boolean.xor(true, true) // => false
291 * Boolean.xor(true, false) // => true
292 * Boolean.xor(false, true) // => true
293 * Boolean.xor(false, false) // => false
294 * ```
295 *
296 * @category combinators
297 * @since 2.0.0
298 */
299export const xor: {
300 (that: boolean): (self: boolean) => boolean
301 (self: boolean, that: boolean): boolean
302} = dual(2, (self: boolean, that: boolean): boolean => (!self && that) || (self && !that))
303
304/**
305 * Combines two booleans using EQV (aka XNOR): `!xor(self, that)`.
306 *
307 * **When to use**
308 *
309 * Use to accept when both boolean operands have the same truth value.
310 *
311 * **Example** (Checking boolean equivalence)
312 *
313 * ```ts import.meta.vitest
314 * import { Boolean } from "effect"
315 *
316 * Boolean.eqv(true, true) // => true
317 * Boolean.eqv(true, false) // => false
318 * Boolean.eqv(false, true) // => false
319 * Boolean.eqv(false, false) // => true
320 * ```
321 *
322 * @category combinators
323 * @since 2.0.0
324 */
325export const eqv: {
326 (that: boolean): (self: boolean) => boolean
327 (self: boolean, that: boolean): boolean
328} = dual(2, (self: boolean, that: boolean): boolean => !xor(self, that))
329
330/**
331 * Combines two booleans using an implication: `(!self || that)`.
332 *
333 * **When to use**
334 *
335 * Use to model logical implication between a condition and a consequence.
336 *
337 * **Example** (Checking boolean implication)
338 *
339 * ```ts import.meta.vitest
340 * import { Boolean } from "effect"
341 *
342 * Boolean.implies(true, true) // => true
343 * Boolean.implies(true, false) // => false
344 * Boolean.implies(false, true) // => true
345 * Boolean.implies(false, false) // => true
346 * ```
347 *
348 * @category combinators
349 * @since 2.0.0
350 */
351export const implies: {
352 (that: boolean): (self: boolean) => boolean
353 (self: boolean, that: boolean): boolean
354} = dual(2, (self, that) => self ? that : true)
355
356/**
357 * Checks whether every boolean in a collection is `true`.
358 *
359 * **When to use**
360 *
361 * Use to check that every boolean in an iterable is `true`.
362 *
363 * **Example** (Checking every boolean)
364 *
365 * ```ts import.meta.vitest
366 * import { Boolean } from "effect"
367 *
368 * Boolean.every([true, true, true]) // => true
369 * Boolean.every([true, false, true]) // => false
370 * ```
371 *
372 * @see {@link some} for checking whether at least one value is `true`
373 * @see {@link ReducerAnd} for reducing booleans with AND through a `Reducer`
374 *
375 * @category predicates
376 * @since 2.0.0
377 */
378export const every = (collection: Iterable<boolean>): boolean => {
379 for (const b of collection) {
380 if (!b) {
381 return false
382 }
383 }
384 return true
385}
386
387/**
388 * Checks whether at least one boolean in a collection is `true`.
389 *
390 * **When to use**
391 *
392 * Use to check that at least one boolean in an iterable is `true`.
393 *
394 * **Example** (Checking some booleans)
395 *
396 * ```ts import.meta.vitest
397 * import { Boolean } from "effect"
398 *
399 * Boolean.some([true, false, true]) // => true
400 * Boolean.some([false, false, false]) // => false
401 * ```
402 *
403 * @see {@link every} for checking whether all values are `true`
404 * @see {@link ReducerOr} for reducing booleans with OR through a `Reducer`
405 *
406 * @category predicates
407 * @since 2.0.0
408 */
409export const some = (collection: Iterable<boolean>): boolean => {
410 for (const b of collection) {
411 if (b) {
412 return true
413 }
414 }
415 return false
416}
417
418/**
419 * Reducer for combining `boolean`s using AND.
420 *
421 * **When to use**
422 *
423 * Use to require every accumulated boolean to be `true` through APIs that
424 * consume a `Reducer`.
425 *
426 * **Details**
427 *
428 * The `initialValue` is `true`, so `combineAll([])` returns `true`.
429 *
430 * **Gotchas**
431 *
432 * `combineAll` uses the default left-to-right `Reducer.make` fold and does not
433 * short-circuit on `false`.
434 *
435 * @see {@link ReducerOr} for reducing with OR semantics
436 * @see {@link every} for checking an iterable directly
437 *
438 * @category math
439 * @since 4.0.0
440 */
441export const ReducerAnd: Reducer.Reducer<boolean> = Reducer.make((a, b) => a && b, true)
442
443/**
444 * Reducer for combining `boolean`s using OR.
445 *
446 * **When to use**
447 *
448 * Use to reduce boolean values where the result should be `true` if any
449 * combined value is `true`.
450 *
451 * **Details**
452 *
453 * The `initialValue` is `false`.
454 *
455 * @see {@link ReducerAnd} for reducing with AND semantics
456 * @see {@link some} for checking an iterable directly
457 *
458 * @category math
459 * @since 4.0.0
460 */
461export const ReducerOr: Reducer.Reducer<boolean> = Reducer.make((a, b) => a || b, false)