Reputation: 789
I want to traverse a String in the following way:
import cats.implicits._
object RnaTranscription {
val mMap: Map[Char, Option[Char]] =
Map('G' -> Some('C'),
'C' -> Some('G'),
'T' -> Some('A'),
'A' -> Some('U')).withDefaultValue(None)
def toRna(dna: String): Option[String] = {
dna.toList.traverse(mMap).map(_.mkString)
}
}
But it has extra steps, I need to cast to a List[Char]
and then mkString
again, is there a way in cats or scalaz to traverse a String without casting to list?
Upvotes: 2
Views: 146
Reputation: 4779
As @BogdanVakulenko implied in his answer, String
is not a Functor (F[_]
).
The Traverse
typeclass in cats had the following declaration:
@typeclass trait Traverse[F[_]] extends Functor[F] with Foldable[F] with UnorderedTraverse[F] { self => ... }
The way that you have solved it with toList
and mkString
is fine by me, but, if you'd like a plain vanilla Scala version that works is:
def toRnaScala(dna: String): Option[String] = {
val maybeChars: immutable.Seq[Option[Char]] = dna.map(mMap)
maybeChars.foldLeft(Option("")) {
case (acc, Some(c)) => acc.map(_ + c)
case (_, None) => None
}
}
Upvotes: 4
Reputation: 3390
Maybe something like this:
def toRna(dna: String): Option[String] = {
Some(dna.map(mMap).flatten.mkString)
}
There is no way to use traverse on string directly as string is native java structure. There is an implicit conversion inside cats/scalaz that adds traverse method to collections. This implicit can be applied only for types with one type parameter ((* -> *) or F[_]
). String is just a T, so scala cant apply this implicit conversion.
implicit def toTraverseOps[F[_], C](target : F[C])
(implicit tc : cats.Traverse[F]) : Traverse.Ops[F, C]
Upvotes: 2