// Again, no AST for python easily available
class PythonLanguage extends LanguageAbstraction {
  type Term = String
  type Apply = String
}

// Still stringy, :fingerscrossed:
implicit object pythonOptional extends MonadF[PythonLanguage, Option] {
  def map[First <: String, Func <: String, From, To](f: Phantom[Func, PythonLanguage, From => To])(fa: Phantom[First, PythonLanguage, Option[From]]) =
    Phantom[String, PythonLanguage, Option[To]](s"(lambda x: (${f.value})(x) if x is not None else x)(${fa.value})")
  def flatMap[First <: String, Func <: String, From, To](f: Phantom[Func, PythonLanguage, From => Option[To]])(fa: Phantom[First, PythonLanguage, Option[From]]) =
    Phantom[String, PythonLanguage, Option[To]](s"(lambda x: (${f.value})(x) if x is not None else x)(${fa.value})")
}

// Convenience method
def liftPy[Z] = lift[PythonLanguage, Z]

// Dataflow
val fa = liftPy[Option[Int]]("5")
val f = liftPy[Int => Option[Int]]("lambda a: a if a >= 0 else None")
val f2 = liftPy[Int => Int]("lambda a: a + 1")

println(fa.flatMap(f).map(f2).value)
// Prints (lambda x: (lambda a: a + 1)(x) if x is not None else x)((lambda x: (lambda a: a if a >= 0 else None)(x) if x is not None else x)(5))