Search code examples
scalamonadsfunctorscalazkind-projector

Lifting a function to ~> in scalaz


I have the following types and declarations:

import scalaz._, Scalaz._

trait Container[T] 
type FreeContainer[A] = Free[Container, A]
type FreeFreeContainer[A] = Free[FreeContainer, A]

val fc: FreeContainer[Int]
val ffc: FreeFreeContainer[Int]

val t: Container ~> Id

val tranformed: Int = fc.foldMap(t)   //ok
val tranformed2: Int = ffc.foldMap(t) //error

Is it possible to lift Container ~> Id to FreeContainer ~> Id?


Solution

  • Yes, via foldMap:

    val t: Container ~> Id
    
    val tt: FreeContainer ~> Id = new (FreeContainer ~> Id) {
      def apply[A](fc: FreeContainer[A]): A = fc.foldMap(t)
    }
    

    Using the polymorphic lambda syntax of kind-projector, this can be simplified to

    val tt: FreeContainer ~> Id = λ[FreeContainer ~> Id](_.foldMap(t))
    

    So you can do

    val tranformed2: Int = ffc.foldMap(λ[FreeContainer ~> Id](_.foldMap(t)))
    

    Alternatively, you can just do two consecutive foldMaps, the first one with the identity natural transformation:

    val tranformed2: Int = ffc.foldMap(NaturalTransformation.refl[FreeContainer]).foldMap(t)