Percursos
/
Scala
Scala
/
Exercícios
/
Contagem de nucleótidos
Contagem de nucleótidos

Contagem de nucleótidos

Médio

Instruções

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 os nossos corpos são construídos. Toda a vida conhecida depende do DNA!

Nota: não precisas de perceber nada sobre nucleótidos ou DNA para completar este exercício.

O DNA é uma longa cadeia de outros químicos e os mais importantes são os quatro nucleótidos: adenina, citosina, guanina e timina. Uma única cadeia de DNA pode conter milhares de milhões destes quatro nucleótidos e a ordem em que ocorrem é importante! Chamamos "sequência de DNA" à ordem destes nucleótidos num pedaço de DNA.

Representamos uma sequência de DNA como uma coleção ordenada destes quatro nucleótidos e uma forma comum de o fazer é com uma string de carateres, como "ATTACG" para uma sequência de DNA de 6 nucleótidos. 'A' de adenina, 'C' de citosina, 'G' de guanina e 'T' de timina.

Dada uma string que representa uma sequência de DNA, conta quantos de cada nucleótido estão presentes. Se a string contiver carateres que não sejam A, C, G ou T, então é inválida e deves assinalar 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 num erro (se o erro em si não tiver interesse, então o tipo mais simples Option pode ser uma escolha melhor). Na ausência de um erro, o resultado costuma ser um Right (mnemónica: o valor "certo"), enquanto um erro é um Left, por exemplo um Left[String] que contém uma mensagem de erro. Repara que, no Scala 2.12, Either é orientado à direita por omissão, por isso funciona como esperado em operações como filter, map, flatMap ou numa compreensão for. Se não estás familiarizado com Either, podes ler este tutorial. Mas tem em atenção que este tutorial é sobre versões de Scala anteriores à 2.12. Para Scala 2.12, podes ignorar RightProjection sem problemas e omitir .right. Either é aquilo a que se chama uma mónada, que abrange um "aspeto computacional", neste caso o tratamento de erros. O uso correto de mónadas pode resultar em código muito conciso, mas ainda assim elegante e legível. O uso incorreto pode facilmente resultar no contrário. Vê este vídeo para saber mais.

Armadilhas comuns que deves evitar

Há algumas regras básicas para Either:

  1. Se não precisares dele, não o uses. Em vez de
def add1(x: Int): Either[String, Int] = Right(x + 1)

é preferível:

def add1(x: Int): Int = x + 1

(há Either.map para aplicar funções simples como estas, por isso não precisas de as sobrecarregar com Either).

  1. Não faças "unwrap" se não precisares mesmo. Muitas vezes há funções incorporadas para o teu objetivo. Indicadores de unwrap prematuro são isLeft/isRight ou correspondência de padrões. Por exemplo, em vez de
val 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
}

é preferível:

x fold (identity, _ + 1)
  1. As mónadas podem ser usadas dentro de uma compreensão for, e isso é ótimo. Isto é aconselhável quando queres "compor" várias instâncias de Either. Em vez de
val 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)))

é preferível:

for {
  x <- xo
  y <- yo
  z <- zo
} yield x + y + z
Editar via GitHub A ligação abre numa nova janela ou separador
Scala Exercism

Estás pronto para começar Contagem de nucleótidos?

Inscreve-te no Exercism para aprenderes e dominares Scala com 95 exercícios, e mentoria humana real, tudo grátis.