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[Φ,α])