Cada um de nós herda dos nossos pais biológicos um conjunto de instruções químicas conhecidas como DNA, que influenciam a forma como o nosso corpo é construído. Toda a vida conhecida depende do DNA!
Observação: você não precisa entender nada sobre nucleotídeos ou DNA para completar este exercício.
O DNA é uma longa cadeia de outras substâncias químicas, e as mais importantes são os quatro nucleotídeos: adenina, citosina, guanina e timina. Uma única cadeia de DNA pode conter bilhões desses quatro nucleotídeos, e a ordem em que eles aparecem é importante! Chamamos a ordem desses nucleotídeos em um trecho de DNA de "sequência de DNA".
Representamos uma sequência de DNA como uma coleção ordenada desses quatro nucleotídeos, e uma forma comum de fazer isso é com uma string de caracteres como "ATTACG" para uma sequência de DNA de 6 nucleotídeos. 'A' para adenina, 'C' para citosina, 'G' para guanina e 'T' para timina.
Dada uma string que representa uma sequência de DNA, conte quantos de cada nucleotídeo estão presentes. Se a string contiver caracteres que não sejam A, C, G ou T, ela é inválida e você deve sinalizar um erro.
Por exemplo:
"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2
"INVALID" -> error
Um uso comum de Either é indicar uma computação que pode resultar em erro
(se o erro em si não interessa, o tipo mais simples Option pode ser uma escolha melhor).
Quando não há erro, o resultado costuma ser um Right (mnemônico: o valor "certo"),
enquanto um erro é um Left, por exemplo um Left[String] contendo uma mensagem de erro.
Repare que no Scala 2.12 o Either é enviesado para a direita por padrão, então ele funciona como esperado em operações como filter, map, flatMap ou em uma for-comprehension.
Se você não conhece Either, pode ler este tutorial. Mas atenção: esse tutorial é sobre versões do Scala anteriores à 2.12. No Scala 2.12, você pode ignorar RightProjection sem problemas e omitir o .right.
Either é uma chamada mônada que cobre um "aspecto computacional",
neste caso o tratamento de erros.
O uso adequado de mônadas pode resultar em um código bem conciso, mas ainda assim elegante
e legível. O uso inadequado pode facilmente resultar no contrário.
Assista a este vídeo para saber mais.
Há algumas regras práticas para Either:
def add1(x: Int): Either[String, Int] = Right(x + 1)
prefira
def add1(x: Int): Int = x + 1
(existe Either.map para aplicar funções simples assim,
então você não precisa sobrecarregá-las com Either).
isLeft/isRight ou pattern matching. Por exemplo, em vez deval x: Either[String, Int] = ...
if (x.isRight) x.right.get + 1 else x.left.get
// or
x match {
case Right(n) => n + 1
case Left(s) => s
}
prefira
x fold (identity, _ + 1)
Either. Em vez deval xo: Either[String, Int] = ...
val yo: Either[String, Int] = ...
val zo: Either[String, Int] = ...
xo.flatMap(x =>
yo.flatMap(y =>
zo.map(z =>
x + y + z)))
prefira
for {
x <- xo
y <- yo
z <- zo
} yield x + y + z
Crie sua conta no Exercism para aprender e dominar Scala com 95 exercícios e mentoria humana de verdade, tudo de graça.