scala/ScalaBook/chapter-03/higherOrder2.scala

def id[α](x: α) = x

trait Fix[Φ[_,_],α]

case class In[Φ[_,_],α](out:Φ[α,Fix[Φ,α]]) extends Fix[Φ[_,_],α]

trait BiFunctor[Φ[_,_]] {
  def bimap[α,β,γ,δ]: (α => β) => (γ => δ) => Φ[α,γ] => Φ[β,δ]
  def fmap2[α,γ,δ]: (γ => δ) => Φ[α,γ] => Φ[α,δ] = bimap(id[α])
}

def map[α,β,Φ[_,_]] (f: α => β) (t: Fix[Φ,α]) (implicit ft: BiFunctor [Φ]): Fix [Φ,β] =
  In[Φ,β] (ft.bimap(f)(map [α,β,Φ](f))(t.out))

def cata[α,ρ,Φ[_,_]] (f: Φ[α,ρ] => ρ) (t: Fix[Φ,α])(implicit ft: BiFunctor[Φ]): ρ =
  f(ft.fmap2(cata[α,ρ,Φ](f))(t.out))

def ana[α,ρ,Φ[_,_]](f: ρ => Φ[α,ρ])(x : ρ)(implicit ft: BiFunctor[Φ]): Fix[Φ,α] =
  In[Φ,α](ft.fmap2(ana[α,ρ,Φ](f))(f(x)))


def hylo[α,β,γ,Φ[_,_]](f: α => Φ[γ,α])(g: Φ[γ,β] => β)(x: α)(implicit ft: BiFunctor[Φ]): β =
  g(ft.fmap2(hylo[α,β,γ,Φ](f)(g))(f(x)))
def build[α,Φ[_,_]](f: {def apply[β]:(Φ[α,β] => β) => β} ) = f.apply(In[Φ,α])