``````trait RelativeMonad[I[_], F[_]] {
def pure[A](ja: I[A]): F[A]

def flatMap[A, B](ma: F[A])(f: I[A] => F[B]): F[B]

def tailRecM[A, B](a: I[A])(f: I[A] => F[Either[A, B]]): F[B]
}``````
``````import cats.MonadError

def pure[A](ja: Either[E, A]): F[A] = ja match {
case Left(e) => F.raiseError[A](e)
case Right(a) => F.pure[A](a)
}

def flatMap[A, B](ma: F[A])(f: Either[E, A] => F[B]): F[B] =
F.flatMap(F.attempt(ma))(f)

def tailRecM[A, B](a: Either[E, A])(f: Either[E, A] => F[Either[A, B]]): F[B] =
a match {
case Left(e) => F.raiseError(e)
case Right(a) => F.tailRecM(a)(a => f(Right(a)))
}
}

def pure[A](x: A): F[A] =
F.pure(Right(x))

def raiseError[A](e: E): F[A] =
F.pure(Left(e))

def flatMap[A, B](fa: F[A])(f: (A) => F[B]): F[B] = F.flatMap(fa) {
case Right(x) => f(x)
case Left(e) => F.pure(Left(e))
}

def handleErrorWith[A](fa: F[A])(f: (E) => F[A]): F[A] = F.flatMap(fa) {
case Right(x) => F.pure(Right(x))
case Left(e) => f(e)
}

def tailRecM[A, B](a: A)(f: A => F[Either[A, B]]): F[B] =
F.tailRecM(Right(a)) {
case Left(e) => raiseError(e)
case Right(a) => f(a)
}
}``````