```package scalaz

trait Cojoin[M[_]] {
def cojoin[A](a: M[A]): M[M[A]]
}

object Cojoin {
import Scalaz._

implicit def IdentityCojoin: Cojoin[Identity] = new Cojoin[Identity] {
def cojoin[A](a: Identity[A]) = a
}

implicit def NonEmptyListCojoin: Cojoin[NonEmptyList] = new Cojoin[NonEmptyList] {
def cojoin[A](a: NonEmptyList[A]) = a.tails
}

implicit def Tuple1Cojoin: Cojoin[Tuple1] = new Cojoin[Tuple1] {
def cojoin[A](a: Tuple1[A]) = Tuple1(a)
}

implicit def Tuple2Cojoin[R]: Cojoin[({type λ[α]=(R, α)})#λ] = new Cojoin[({type λ[α]=(R, α)})#λ] {
def cojoin[A](a: (R, A)) = (a._1, a)
}

implicit def Function0Cojoin: Cojoin[Function0] = new Cojoin[Function0] {
def cojoin[A](a: () => A) = () => a
}

import java.util.concurrent.Callable

implicit def CallableCojoin: Cojoin[Callable] = new Cojoin[Callable] {
def cojoin[A](a: Callable[A]) = new Callable[Callable[A]] {
def call = a
}
}

import java.util.Map.Entry
import java.util.AbstractMap.SimpleImmutableEntry

implicit def MapEntryCojoin[X]: Cojoin[({type λ[α]=Entry[X, α]})#λ] = new Cojoin[({type λ[α]=Entry[X, α]})#λ] {
def cojoin[A](a: Entry[X, A]) = new SimpleImmutableEntry(a.getKey, a)
}

implicit def ZipperCojoin: Cojoin[Zipper] = new Cojoin[Zipper] {
def cojoin[A](a: Zipper[A]) = a.positions
}

implicit def TreeCojoin: Cojoin[Tree] = new Cojoin[Tree] {
def cojoin[A](a: Tree[A]): Tree[Tree[A]] = a.cobind(identity(_))
}

implicit def TreeLocCojoin: Cojoin[TreeLoc] = new Cojoin[TreeLoc] {
def cojoin[A](a: TreeLoc[A]): TreeLoc[TreeLoc[A]] = {
val lft = (_: TreeLoc[A]).left
val rgt = (_: TreeLoc[A]).right
val p = a.parent.unfold[Stream, (Stream[Tree[TreeLoc[A]]], TreeLoc[A], Stream[Tree[TreeLoc[A]]])]((o: Option[TreeLoc[A]]) =>
for (z <- o) yield ((uf(z, lft), z, uf(z, rgt)), z.parent))
loc(a.unfoldTree(dwn[A](_: TreeLoc[A])), uf(a, lft), uf(a, rgt), p)
}

private def uf[A](a: TreeLoc[A], f: TreeLoc[A] => Option[TreeLoc[A]]): Stream[Tree[TreeLoc[A]]] =
f(a).unfold[Stream, Tree[TreeLoc[A]]]((o: Option[TreeLoc[A]]) =>
for (c <- o) yield (c.unfoldTree(dwn[A](_: TreeLoc[A])), f(c)))

private def dwn[A](tz: TreeLoc[A]): (TreeLoc[A], () => Stream[TreeLoc[A]]) =
(tz, () => tz.firstChild.unfold[Stream, TreeLoc[A]]((o: Option[TreeLoc[A]]) =>
for (c <- o) yield (c, c.right)))
}

import concurrent.Promise
implicit def PromiseCojoin: Cojoin[Promise] = new Cojoin[Promise] {
def cojoin[A](a: Promise[A]) = promise(a)(a.strategy)
}
}

```