diff --git a/src/algebra/free.js b/src/algebra/free.js
index 536ed01..dd5d584 100644
--- a/src/algebra/free.js
+++ b/src/algebra/free.js
@@ -1,7 +1,7 @@
-import { Algebra, Monad } from './interfaces.js'
+import { Algebra, Foldable, Monad, Traversable } from './interfaces.js'
 import { curry } from '../..//vendor/izuna/src/index.js'
 
-/** @import { Applicative, ApplicativeTypeRef, Morphism } from './types.js' */
+/** @import { Applicative, ApplicativeTypeRef, Apply, Chain, Foldable as FoldableT, Functor, Monad as MonadT, Morphism, Traversable as TraversableT } from './types.js' */
 
 
 /** @import { InferredMorphism } from './types.js' */
@@ -12,7 +12,7 @@ const kleisli = curry((f, g, x) => f(x).chain(g))
  * @template T
  * @type {Pure<T> | Impure<T>} Free
  */
-export class Free extends Algebra(Monad) {
+export class Free {
   /**
    * @template T
    * @param {T} value 
@@ -23,7 +23,7 @@ export class Free extends Algebra(Monad) {
 }
 
 /** @template T */
-export class Pure extends Free {
+export class Pure extends Algebra(Monad, Traversable) {
   #value
 
   /**
@@ -48,13 +48,29 @@ export class Pure extends Free {
     return pure(f(this.#value))
   }
 
+  /**
+   * @template U
+   * @this {Pure<Morphism<U, T>>}
+   * @param {Free<T>} b 
+   */
+  ap(b) {
+    return b.map(this.#value)
+  }
+
+  /**
+   * @type {FoldableT<T>['reduce']}
+   */
+  reduce(f, acc) {
+    return f(acc, this.#value)
+  }
+
   /**
    * @template U
    * @template {Applicative<U>} M
    * @template {ApplicativeTypeRef<U, M>} TypeRef
    * @param {TypeRef} _A
-   * @param {*} f
-   * @returns {M}
+   * @param {(value: T) => M} f
+   * @returns {Applicative<Free<U>>}
    */
   traverse(_A, f) {
     return f(this.#value).map(pure)
@@ -65,14 +81,19 @@ export class Pure extends Free {
   }
 }
 
-/** @template T */
-export class Impure extends Free {
+/**
+ * @template T, [N=any]
+ * @implements Functor<T>
+ * @implements Chain<T>
+ * @implements TraversableT<T>
+ */
+export class Impure extends Algebra(Monad, Foldable, Traversable) {
   #value
   #next
 
   /**
    * @param {T} value 
-   * @param {(value: T) => Free<any>} f 
+   * @param {(value: T) => Free<N>} f 
    */
   constructor(value, f) {
     super()
@@ -81,26 +102,56 @@ export class Impure extends Free {
   }
 
   /**
-   * @param {<U>(value: T) => Free<U>} f 
+   * @type {Chain<T>['chain']}
+   * @template U
+   * @param {(value: T) => Free<U>} f 
+   * @returns {Chain<T>}
    */
   chain(f) {
     return impure(this.#value, kleisli(this.#next, f))
   }
 
+  /**
+   * @template {Functor<T>} U
+   * @type {Functor<T>['map']}
+   * @param {(value: T) => U} f 
+   * @returns {Functor<T>}
+   */
   map(f) {
     return impure(
       this.#value,
-      y => f(y).chain(f)
+      y => f(y).map(f)
     )
   }
 
   /**
+   * @type {Apply<T>['ap']}
+   */
+  ap(b) {
+    return this.chain(f => b.map(f))
+  }
+
+  /**
+   * @type {FoldableT<T>['reduce']}
+   */
+  reduce(f, acc) {
+    const fb = f(acc, this.#value)
+    const rest = this.#next(this.#value).reduce(f, acc)
+
+    return rest.ap(
+      fb.map(b => next => impure(b, () => next))
+    )
+  }
+
+  /**
+   * @type {TraversableT<T>['traverse']}
    * @template U
    * @template {Applicative<U>} M
    * @template {ApplicativeTypeRef<U, M>} TypeRef
+   * @this {Impure<T, N>}
    * @param {TypeRef} A
-   * @param {(value: T) => M} f
-   * @returns {M}
+   * @param {(value: T | N) => M} f
+   * @returns {Applicative<Free<U>>}
    */
   traverse(A, f) {
     const fb = f(this.#value)
@@ -131,6 +182,7 @@ const pure = x => new Pure(x)
  */
 const impure = (x, f) => new Impure(x, f)
 
+
 /**
  * @template T
  * @param {T} x
diff --git a/src/algebra/types.js b/src/algebra/types.js
index d8b95d6..9378ddf 100644
--- a/src/algebra/types.js
+++ b/src/algebra/types.js
@@ -100,9 +100,10 @@ export default {}
 
 /**
  * @template T
- * @typedef {{
-     ap: <U>(f: Apply<Morphism<T, U>>) => Apply<U>
- * }} Apply
+ * @typedef {
+     Functor<T> &
+     { ap: <U>(f: Apply<Morphism<T, U>>) => Apply<U> }
+ * } Apply
  */
 
 /**
@@ -157,7 +158,7 @@ export default {}
 /**
  * @template T
  * @typedef {{
-     filter: <U>(f: (acc: U, val: T) => U, init: U) => U
+     reduce: <U>(f: (acc: U, val: T) => U, init: U) => U
  * }} Foldable
  */
 
diff --git a/src/union.js b/src/union.js
index b5e6a39..4c95d0b 100644
--- a/src/union.js
+++ b/src/union.js
@@ -77,15 +77,16 @@ function is(other) {
 }
 
 /**
- * @template {PropertyKey} const T
+ * @template {string} const T
  * @template {Array<PropertyKey>} const U
  * @param {T} typeName
  * @param {...U} variantNames
  * @returns {Union<T, U>}
  */
 export const Union = (typeName, variantNames) => {
-  const tag = { [Tag]: typeName, is }
-  const variants = Object.fromEntries(variantNames.map(v => [v, Variant(typeName, v)]))
+  const typeTag = Symbol(typeName)
+  const tag = { [Tag]: typeTag, is }
+  const variants = Object.fromEntries(variantNames.map(v => [v, Variant(typeTag, v)]))
   const result = Object.assign(tag, variants)