import * as Tp from "../Collections/Immutable/Tuple"
import type { Either } from "../Either/core"
import type { Lazy, Predicate, Refinement } from "../Function/core"
import * as St from "../Structural"
/**
 * Definitions
 */
export declare class None {
  readonly _tag = "None";
  [St.equalsSym](that: unknown): boolean
  get [St.hashSym](): number
}
export declare class Some<A> {
  readonly value: A
  readonly _tag = "Some"
  constructor(value: A)
  [St.equalsSym](that: unknown): boolean
  get [St.hashSym](): number
}
export declare type Option<A> = None | Some<A>
/**
 * Constructs none
 */
export declare const none: Option<never>
/**
 * Constructs none
 */
export declare const emptyOf: <A>() => Option<A>
/**
 * Constructs Some(A)
 */
export declare function some<A>(a: A): Option<A>
/**
 * Classic applicative
 */
export declare const ap_: <A, B>(fab: Option<(a: A) => B>, fa: Option<A>) => Option<B>
/**
 * Classic applicative
 */
export declare const ap: <A>(
  fa: Option<A>
) => <B>(fab: Option<(a: A) => B>) => Option<B>
/**
 * Zips `Option[A]` and `Option[B]` into `Option[(A, B)]
 */
export declare const zip_: <A, B>(
  fa: Option<A>,
  fb: Option<B>
) => Option<Tp.Tuple<[A, B]>>
/**
 * Zips `Option[A]` and `Option[B]` into `Option[(A, B)]
 */
export declare const zip: <B>(
  fb: Option<B>
) => <A>(fa: Option<A>) => Option<Tp.Tuple<[A, B]>>
/**
 * Apply both and return first
 */
export declare const zipFirst: <B>(fb: Option<B>) => <A>(fa: Option<A>) => Option<A>
/**
 * Apply both and return second
 */
export declare const zipSecond: <B>(fb: Option<B>) => <A>(fa: Option<A>) => Option<B>
/**
 * Builds a new option constructed using the value of self
 */
export declare const chain_: <A, B>(
  self: Option<A>,
  f: (a: A) => Option<B>
) => Option<B>
/**
 * Builds a new option constructed using the value of self
 */
export declare const chain: <A, B>(
  f: (a: A) => Option<B>
) => (self: Option<A>) => Option<B>
/**
 * Like chain but ignores the constructed outout
 */
export declare const tap: <A>(f: (a: A) => Option<any>) => (ma: Option<A>) => Option<A>
/**
 * Like chain but ignores the constructed outout
 */
export declare const tap_: <A>(ma: Option<A>, f: (a: A) => Option<any>) => Option<A>
/**
 * Flattens nested options
 */
export declare const flatten: <A>(fa: Option<Option<A>>) => Option<A>
/**
 * Wraps this option into a second one
 */
export declare const duplicate: <A>(ma: Option<A>) => Option<Option<A>>
/**
 * Returns `true` if the predicate is satisfied by the wrapped value
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     exists(n => n > 0)
 *   ),
 *   true
 * )
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     exists(n => n > 1)
 *   ),
 *   false
 * )
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     exists(n => n > 0)
 *   ),
 *   false
 * )
 */
export declare function exists<A>(predicate: Predicate<A>): (ma: Option<A>) => boolean
/**
 * Apply `Option[A] => B` in case self is some returning `Option[B]`
 */
export declare const extend: <A, B>(
  f: (fa: Option<A>) => B
) => (self: Option<A>) => Option<B>
/**
 * Apply `Option[A] => B` in case self is some returning `Option[B]`
 */
export declare const extend_: <A, B>(
  self: Option<A>,
  f: (fa: Option<A>) => B
) => Option<B>
/**
 * Takes a default value, a function, and an `Option` value, if the `Option` value is `None` the default value is
 * returned, otherwise the function is applied to the value inside the `Some` and the result is returned.
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     fold(() => 'a none', a => `a some containing ${a}`)
 *   ),
 *   'a some containing 1'
 * )
 *
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     fold(() => 'a none', a => `a some containing ${a}`)
 *   ),
 *   'a none'
 * )
 */
export declare function fold<A, B, C>(
  onNone: () => B,
  onSome: (a: A) => C
): (ma: Option<A>) => B | C
/**
 * Takes a default value, a function, and an `Option` value, if the `Option` value is `None` the default value is
 * returned, otherwise the function is applied to the value inside the `Some` and the result is returned.
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     fold(() => 'a none', a => `a some containing ${a}`)
 *   ),
 *   'a some containing 1'
 * )
 *
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     fold(() => 'a none', a => `a some containing ${a}`)
 *   ),
 *   'a none'
 * )
 */
export declare function fold_<A, B, C>(
  ma: Option<A>,
  onNone: () => B,
  onSome: (a: A) => C
): B | C
/**
 * Constructs `Option[A]` from `Either[E, A]` discarding `E`
 */
export declare const fromEither: <E, A>(ma: Either<E, A>) => Option<A>
/**
 * Constructs a new `Option` from a nullable type. If the value is `null` or `undefined`, returns `None`, otherwise
 * returns the value wrapped in a `Some`
 *
 * @example
 * assert.deepStrictEqual(fromNullable(undefined), none)
 * assert.deepStrictEqual(fromNullable(null), none)
 * assert.deepStrictEqual(fromNullable(1), some(1))
 */
export declare function fromNullable<A>(a: A): Option<NonNullable<A>>
/**
 * Returns a smart constructor based on the given predicate
 *
 * @example
 * import { none, some, fromPredicate } from '@matechs/core/Option'
 *
 * const getOption = fromPredicate((n: number) => n >= 0)
 *
 * assert.deepStrictEqual(getOption(-1), none)
 * assert.deepStrictEqual(getOption(1), some(1))
 */
export declare function fromPredicate<A, B extends A>(
  refinement: Refinement<A, B>
): (a: A) => Option<B>
export declare function fromPredicate<A>(predicate: Predicate<A>): (a: A) => Option<A>
/**
 * Returns an `E` value if possible
 */
export declare function getLeft<E, A>(ma: Either<E, A>): Option<E>
/**
 * Extracts the value out of the structure, if it exists. Otherwise returns the given default value
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     getOrElse(() => 0)
 *   ),
 *   1
 * )
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     getOrElse(() => 0)
 *   ),
 *   0
 * )
 */
export declare function getOrElse<B>(onNone: () => B): <A>(ma: Option<A>) => A | B
/**
 * Extracts the value out of the structure, if it exists. Otherwise returns the given default value
 */
export declare function getOrElseInv<B>(onNone: () => B): (ma: Option<B>) => B
/**
 * Extracts the value out of the structure, if it exists. Otherwise returns the given default value
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     getOrElse(() => 0)
 *   ),
 *   1
 * )
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     getOrElse(() => 0)
 *   ),
 *   0
 * )
 */
export declare function getOrElse_<A, B>(ma: Option<A>, onNone: () => B): A | B
/**
 * Extracts the value out of the structure, if it exists. Otherwise returns the given default value
 */
export declare function getOrElseInv_<A>(ma: Option<A>, onNone: () => A): A
/**
 * Returns a `Refinement` (i.e. a custom type guard) from a `Option` returning function.
 * This function ensures that a custom type guard definition is type-safe.
 *
 * ```ts
 * type A = { type: 'A' }
 * type B = { type: 'B' }
 * type C = A | B
 *
 * const isA = (c: C): c is A => c.type === 'B' // <= typo but typescript doesn't complain
 * const isA = getRefinement<C, A>(c => (c.type === 'B' ? some(c) : none)) // static error: Type '"B"' is not assignable to type '"A"'
 * ```
 */
export declare function getRefinement<A, B extends A>(
  getOption: (a: A) => Option<B>
): Refinement<A, B>
/**
 * Returns an `A` value if possible
 */
export declare function getRight<E, A>(ma: Either<E, A>): Option<A>
/**
 * Returns `true` if the option is `None`, `false` otherwise
 *
 * @example
 * assert.strictEqual(isNone(some(1)), false)
 * assert.strictEqual(isNone(none), true)
 */
export declare function isNone<A>(fa: Option<A>): fa is None
/**
 * Returns `true` if the option is an instance of `Some`, `false` otherwise
 *
 * @example
 * assert.strictEqual(isSome(some(1)), true)
 * assert.strictEqual(isSome(none), false)
 */
export declare function isSome<A>(fa: Option<A>): fa is Some<A>
/**
 * Use `A => B` to transform `Option[A]` to `Option[B]`
 */
export declare const map_: <A, B>(fa: Option<A>, f: (a: A) => B) => Option<B>
/**
 * Use `A => B` to transform `Option[A]` to `Option[B]`
 */
export declare const map: <A, B>(f: (a: A) => B) => (fa: Option<A>) => Option<B>
/**
 * This is `chain` + `fromNullable`, useful when working with optional values
 *
 * @example
 * interface Employee {
 *   company?: {
 *     address?: {
 *       street?: {
 *         name?: string
 *       }
 *     }
 *   }
 * }
 *
 * const employee1: Employee = { company: { address: { street: { name: 'high street' } } } }
 *
 * assert.deepStrictEqual(
 *   pipe(
 *     fromNullable(employee1.company),
 *     mapNullable(company => company.address),
 *     mapNullable(address => address.street),
 *     mapNullable(street => street.name)
 *   ),
 *   some('high street')
 * )
 *
 * const employee2: Employee = { company: { address: { street: {} } } }
 *
 * assert.deepStrictEqual(
 *   pipe(
 *     fromNullable(employee2.company),
 *     mapNullable(company => company.address),
 *     mapNullable(address => address.street),
 *     mapNullable(street => street.name)
 *   ),
 *   none
 * )
 */
export declare function mapNullable<A, B>(
  f: (a: A) => B | null | undefined
): (ma: Option<A>) => Option<B>
/**
 * Extracts the value out of the structure, if it exists. Otherwise returns `null`.
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     toNullable
 *   ),
 *   1
 * )
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     toNullable
 *   ),
 *   null
 * )
 */
export declare function toNullable<A>(ma: Option<A>): A | null
/**
 * Extracts the value out of the structure, if it exists. Otherwise returns `undefined`.
 *
 * @example
 * assert.strictEqual(
 *   pipe(
 *     some(1),
 *     toUndefined
 *   ),
 *   1
 * )
 * assert.strictEqual(
 *   pipe(
 *     none,
 *     toUndefined
 *   ),
 *   undefined
 * )
 */
export declare function toUndefined<A>(ma: Option<A>): A | undefined
/**
 * Transforms an exception into an `Option`. If `f` throws, returns `None`, otherwise returns the output wrapped in
 * `Some`
 *
 * @example
 * assert.deepStrictEqual(
 *   tryCatch(() => {
 *     throw new Error()
 *   }),
 *   none
 * )
 * assert.deepStrictEqual(tryCatch(() => 1), some(1))
 */
export declare function tryCatch<A>(f: Lazy<A>): Option<A>
export declare const PartialExceptionTypeId: unique symbol
export declare type PartialExceptionTypeId = typeof PartialExceptionTypeId
export declare class PartialException {
  readonly _typeId: PartialExceptionTypeId
}
/**
 * Simulates a partial function
 */
export declare function partial<ARGS extends any[], A>(
  f: (miss: <X>() => X) => (...args: ARGS) => A
): (...args: ARGS) => Option<A>
//# sourceMappingURL=core.d.ts.map
