All files / src/instances Covariant.ts

100% Statements 48/48
100% Branches 9/9
100% Functions 4/4
100% Lines 48/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 991x 1x 1x     1x 5547x 5547x   5547x 5547x 5547x 5547x 5547x 703x 703x 703x 703x 703x 703x 703x 703x 703x 5547x 5547x   1x 20763x   20763x 20763x 20763x 11787x 11787x 11787x 11787x 11787x 11787x 11787x 11787x 11787x 20763x                     1x                         1x             1x 1x 1x 8972x 1x           1x           1x           1x     1x  
import {Covariant as CO} from '@effect/typeclass'
import {Effect, flow, Function, pipe} from 'effect'
import {branch, leaf, match, tree} from '../tree/index.js'
import type {Tree, TreeTypeLambda} from '../tree/types.js'
 
const _mapEffect = <A, B, E = unknown, R = never>(
  self: Tree<A>,
  f: (a: A) => Effect.Effect<B, E, R>,
): Effect.Effect<Tree<B>, E, R> =>
  pipe(
    self,
    match({
      onLeaf: flow(f, Effect.map(leaf)),
      onBranch: (value, forest) =>
        Effect.suspend(() =>
          pipe(
            forest,
            Effect.forEach(mapEffect(f)),
            Effect.flatMap(forest =>
              pipe(value, f, Effect.map(branch(forest))),
            ),
          ),
        ),
    }),
  )
 
const _mapEffectPreOrder = <A, B, E = unknown, R = never>(
  f: (a: A) => Effect.Effect<B, E, R>,
): ((self: Tree<A>) => Effect.Effect<Tree<B>, E, R>) =>
  match({
    onLeaf: flow(f, Effect.map(leaf)),
    onBranch: (value, forest) =>
      Effect.suspend(() =>
        Effect.flatMap(f(value), value =>
          pipe(
            forest,
            Effect.forEach(mapEffect.pre(f)),
            Effect.map(tree.flipped(value)),
          ),
        ),
      ),
  })
 
/**
 * Map an effectful function over the tree in post-order: parent effect is run
 * _after_ children.
 *
 * At the key `pre` you will find a function that runs the effect in
 * depth-first pre-order.
 * @category instances
 * @function
 */
export const mapEffect: {
  <A, B, E = unknown, R = never>(
    self: Tree<A>,
    f: (a: A) => Effect.Effect<B, E, R>,
  ): Effect.Effect<Tree<B>, E, R>
 
  <A, B, E = unknown, R = never>(
    f: (a: A) => Effect.Effect<B, E, R>,
  ): (self: Tree<A>) => Effect.Effect<Tree<B>, E, R>
 
  pre: <A, B, E = unknown, R = never>(
    f: (a: A) => Effect.Effect<B, E, R>,
  ) => (self: Tree<A>) => Effect.Effect<Tree<B>, E, R>
} = Object.assign(Function.dual(2, _mapEffect), {pre: _mapEffectPreOrder})
 
/**
 * Map over all tree nodes using the given function.
 * @category instances
 * @function
 */
export const map: CO.Covariant<TreeTypeLambda>['map'] = Function.dual(
  2,
  <A, B>(self: Tree<A>, f: (a: A) => B): Tree<B> =>
    pipe(self, mapEffect.pre(flow(f, Effect.succeed)), Effect.runSync),
)
 
/**
 * @category instances
 * @function
 */
export const imap = CO.imap<TreeTypeLambda>(map)
 
/**
 * Covariant instance for {@link Tree}.
 * @category instances
 */
export const Covariant: CO.Covariant<TreeTypeLambda> = {map, imap}
 
/**
 * @category instances
 * @function
 */
export const flap: {
  <A, B>(self: Tree<(a: A) => B>): (a: A) => Tree<B>
  <A, B>(a: A, self: Tree<(a: A) => B>): Tree<B>
} = CO.flap(Covariant)