私たちは皆、生物学的な親からDNAと呼ばれる化学的な設計図を受け継いでいます。これは、私たちの体がどのように作られるかに影響を与えます。知られているすべての生命はDNAに支えられています!
注: この演習を解くために、ヌクレオチドやDNAについて何かを理解している必要はありません。
DNAは他の化学物質が長くつながった鎖であり、もっとも重要なのは4つのヌクレオチド、アデニン、シトシン、グアニン、チミンです。DNAの鎖は1本で、これらの4つのヌクレオチドを何十億個も含むことがあり、それらが現れる順序が重要です! ある部分のDNAにおけるこれらのヌクレオチドの順序を「DNA配列」と呼びます。
DNA配列は、これら4つのヌクレオチドを順番に並べたものとして表します。よく使われるのは、文字の並びで表す方法です。たとえば、6つのヌクレオチドからなるDNA配列は"ATTACG"のようになります。'A'はアデニン、'C'はシトシン、'G'はグアニン、'T'はチミンを表します。
DNA配列を表す文字列が与えられたとき、それぞれのヌクレオチドがいくつあるかを数えましょう。文字列にA、C、G、T以外の文字が含まれている場合は無効なので、エラーを通知してください。
たとえば、次のとおりです。
"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2
"INVALID" -> error
Eitherのよくある使い方は、エラーになる可能性のある計算を表すことです(実際のエラー内容が重要でなければ、よりシンプルなOption型のほうが良い選択かもしれません)。
エラーがない場合、結果は通常Rightです(覚え方:「正しい(right)」の値)。一方、エラーはLeftで、たとえばエラーメッセージを含むLeft[String]のようになります。
Scala 2.12ではEitherはデフォルトで右寄りなので、filterやmap、flatMapといった操作やfor内包表記で期待どおりに動作します。
Eitherに馴染みがない場合は、こちらのチュートリアルを読んでみてください。ただし、このチュートリアルは2.12より前のScalaを対象としている点に注意してください。Scala 2.12では、RightProjectionは無視してよく、.rightも省略できます。
Eitherはいわゆるモナドで、「計算の側面」、ここではエラー処理を担います。
モナドを適切に使うと、簡潔でありながらエレガントで読みやすいコードになります。使い方を誤ると、あっという間に正反対の結果になります。
詳しくはこちらの動画を見てみましょう。
Eitherにはいくつかの経験則があります。
def add1(x: Int): Either[String, Int] = Right(x + 1)
ではなく、
def add1(x: Int): Int = x + 1
としたほうがよいでしょう。
(このような単純な関数を適用するEither.mapがあるので、Eitherでコードを煩雑にする必要はありません。)
2. 本当に必要でなければ「アンラップ」しないこと。
目的に合った組み込み関数が用意されていることがよくあります。早すぎるアンラップの兆候は、isLeft/isRightやパターンマッチングです。たとえば、次のような
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
}
ではなく、
x fold (identity, _ + 1)
としたほうがよいでしょう。
3. モナドはfor内包表記の中でも使えて、とても便利です。
これは、複数のEitherを「合成」したいときにおすすめです。次のような
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)))
ではなく、
for {
x <- xo
y <- yo
z <- zo
} yield x + y + z
としたほうがよいでしょう。