import * as Ap from 'fp-ts/lib/Apply'
import * as Eq from 'fp-ts/lib/Eq'
import * as O from 'fp-ts/lib/Option'
import * as RA from 'fp-ts/lib/ReadonlyArray'
export * from 'fp-ts/lib/ReadonlyArray'
/**
* Unsafely coerce the ReadonlyArray to an Array
*/
export const unsafeCoerceToArray = (
readonlyArray: ReadonlyArray,
): Array => readonlyArray as Array
/**
* Unsafely coerce an Array to a ReadonlyArray
*/
export const unsafeCoerceFromArray = (array: Array): ReadonlyArray =>
array as ReadonlyArray
/**
* Gets the head and tail parts of the array as an object, if possible.
*
* This is often referred to "uncons," as it's the opposite of constructing an array with a head and tail.
*/
export const headAndTailS = (
a: ReadonlyArray,
): O.Option<{ head: A; tail: ReadonlyArray }> =>
Ap.sequenceS(O.option)({ head: RA.head(a), tail: RA.tail(a) })
/**
* Gets the head and tail parts of the array as a tuple, if possible.
*
* This is often referred to "uncons," as it's the opposite of constructing an array with a head and tail.
*/
export const headAndTailT = (
a: ReadonlyArray,
): O.Option<[A, ReadonlyArray]> =>
Ap.sequenceT(O.option)(RA.head(a), RA.tail(a))
/**
* Gets the init and last parts of the array as an object, if possible.
*
* This is like an "uncons" for the end of the array.
*/
export const initAndLastS = (
a: ReadonlyArray,
): O.Option<{ init: ReadonlyArray; last: A }> =>
Ap.sequenceS(O.option)({ init: RA.init(a), last: RA.last(a) })
/**
* Gets the init and last parts of the array as a tuple, if possible.
*
* This is like an "uncons" for the end of the array.
*/
export const initAndLastT = (
a: ReadonlyArray,
): O.Option<[ReadonlyArray, A]> =>
Ap.sequenceT(O.option)(RA.init(a), RA.last(a))
/**
* Returns an array of elements which are in both input arrays but not in their
* intersection. Also known as symmetric difference or disjunctive union.
*/
export const xor = (eq: Eq.Eq) => (
xs: ReadonlyArray,
ys: ReadonlyArray,
) => [...RA.difference(eq)(xs, ys), ...RA.difference(eq)(ys, xs)]