在 cats/scalaz 中遍历一个字符串

traverse a string in cats/scalaz

我想通过以下方式遍历一个字符串:

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)
  }
}

但它有额外的步骤,我需要转换为 List[Char],然后再次转换为 mkString,在 cats 或 scalaz 中有没有一种方法可以在不转换为列表的情况下遍历字符串?

也许是这样的:

def toRna(dna: String): Option[String] = {
  Some(dna.map(mMap).flatten.mkString)
}

无法直接在字符串上使用遍历,因为字符串是原生 java 结构。 cats/scalaz 内部有一个隐式转换,它向集合添加遍历方法。此隐式只能应用于具有一个类型参数((* -> *) 或 F[_])的类型。字符串只是一个 T,因此 Scala 无法应用此隐式转换。

implicit def toTraverseOps[F[_], C](target : F[C])
            (implicit tc : cats.Traverse[F]) : Traverse.Ops[F, C]

正如@BogdanVakulenko 在他的回答中暗示的那样,String 不是 FunctorF[_])。

cats 中的 Traverse 类型类具有以下声明:

@typeclass trait Traverse[F[_]] extends Functor[F] with Foldable[F] with UnorderedTraverse[F] { self => ... }

你用 toListmkString 解决它的方法对我来说很好,但是,如果你想要一个简单的香草 Scala 版本是:

  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
    }
  }