Sequence to Eithers

purely for fun (https://scastie.scala-lang.org/WAJiDyxPRSesWTk8VfzqlA)

def parseInt(s: String): Either[Throwable,Int] = 
  scala.util.Try(s.toInt).toEither

// https://pursuit.purescript.org/packages/purescript-birds/1.0.0/docs/Aviary.Birds#v:cardinal
def cardinal[A,B,C](f: (A, B) => C)(b: B, a: A): C = 
  f(a,b) 

def map2[A,B,C,E](ea: Either[E,A], eb: Either[E,B])(f: (A, B) => C): Either[E,C] =
  for {
    a <- ea
    b <- eb
  } yield f(a, b)

def applyAndCons[E,A,B](f: A => Either[E,B])(head:A,tail:Either[E,Seq[B]]): Either[E,Seq[B]] = 
  map2(f(head),tail)(_ +: _)

def traverse[A,B,E](as: Seq[A])(f: A => Either[E,B]): Either[E,Seq[B]] =
  as.foldRight[Either[E,Seq[B]]](Right(Nil))(applyAndCons(f))

// produces the reverse of traverse
def treverse[A,B,E](as: Seq[A])(f: A => Either[E,B]): Either[E,Seq[B]] =
  as.foldLeft[Either[E,Seq[B]]](Right(Nil))(cardinal(applyAndCons(f)))

assert( traverse(List("1","2","3","4","5"))(parseInt) == Right(List(1,2,3,4,5)) )
assert( treverse(List("1","2","3","4","5"))(parseInt) == Right(List(5,4,3,2,1)) )

def traverse2[A,B,E](as: Seq[A])(f: A => Either[E,B]): Either[E,Seq[B]] =
  treverse(as)(f).map(_.reverse)

assert( traverse2(List("1","2","3","4","5"))(parseInt) 
        ==
        traverse(List("1","2","3","4","5"))(parseInt) )