体は、DNAを含む細胞でできています。 そうした細胞は定期的に古くなり、入れ替わる必要があります。それが、娘細胞に分裂することで行われます。 実際、平均的な人間の体では、一生の間に約1京回もの細胞分裂が起こっています!
細胞が分裂するとき、DNAも複製されます。 この過程でときどき間違いが起こり、DNAの一片に誤った情報が書き込まれてしまうことがあります。 2本のDNAの鎖を比べて、違いの数を数えれば、いくつの間違いが起きたのかがわかります。 これが「ハミング距離」と呼ばれるものです。
ハミング距離は生物学だけでなく、科学の多くの分野で役立つので、覚えておくとよい言葉です :)
2つのDNA鎖の間のハミング距離を計算します。
DNAは、C、A、G、Tという文字で表されます。 2つの鎖は、たとえば次のようになります。
GAGCCTACTAACGGGAT
CATCGTAATGACGGCCT
^ ^ ^ ^ ^ ^^
違いは7か所あるので、ハミング距離は7です。
ハミング距離は、同じ長さの並びに対してのみ定義されています。そのため、長さの異なる並びの間で計算しようとしても、うまくいきません。
Optionは、役に立つ結果が得られないかもしれない計算(たとえばエラーや不正な入力が原因の場合)を表すために使います。
Optionに馴染みがない場合は、このチュートリアルを読んでみてください。
Optionは、いわゆるMonadであり、「計算の側面」、この場合は値が存在しない可能性を扱います。
モナドを適切に使うと、とても簡潔でありながらエレガントで読みやすいコードになります。使い方を誤ると、あっという間に正反対の結果になってしまいます。詳しく知りたい場合はこの動画を見てみましょう。
Optionには、いくつかの経験則があります。
def add1(x: Int): Option[Int] = Some(x + 1)
次のようにしましょう
def add1(x: Int): Int = x + 1
(このような単純な関数を適用するためのOption.mapがあるので、わざわざOptionでコードを煩雑にする必要はありません。)
isDefined/isEmptyやパターンマッチです。次のように書くのではなくval x: Option[Int] = ...
if (x.isDefined) x.get + 1 else 0
// or
x match {
case Some(n) => n + 1
case None => 0
}
次のようにしましょう
x map (_ + 1) getOrElse 0
for内包表記の中で使うのが一番です。これは、複数のOptionインスタンスを「合成」したいときに適しています。次のように書くのではなくval xo: Option[Int] = ...
val yo: Option[Int] = ...
val zo: Option[Int] = ...
xo.flatMap(x =>
yo.flatMap(y =>
zo.map(z =>
x + y + z)))
次のようにしましょう
for {
x <- xo
y <- yo
z <- zo
} yield x + y + z