我們每個人都從親生父母身上繼承了一組稱為 DNA 的化學指令,這些指令影響著我們身體的建構方式。所有已知的生命都依賴 DNA!
注意:你不必了解任何關於核苷酸或 DNA 的知識,就能完成這個練習。
DNA 是一長串由其他化學物質構成的鏈,其中最重要的是四種核苷酸:腺嘌呤、胞嘧啶、鳥嘌呤和胸腺嘧啶。單一條 DNA 鏈可以包含數十億個這四種核苷酸,而它們出現的順序非常重要!我們把一段 DNA 中這些核苷酸的順序稱為「DNA 序列」。
我們將 DNA 序列表示為這四種核苷酸的有序集合,而常見的做法是用一串字元來表示,例如「ATTACG」代表由 6 個核苷酸組成的 DNA 序列。'A' 代表腺嘌呤,'C' 代表胞嘧啶,'G' 代表鳥嘌呤,'T' 代表胸腺嘧啶。
給定一個代表 DNA 序列的字串,計算每種核苷酸各出現多少次。如果字串中包含不是 A、C、G 或 T 的字元,那麼它就是無效的,你應該發出錯誤。
例如:
"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2
"INVALID" -> error
Either常見的用途是表示一個可能會產生錯誤的運算(如果其實不在意錯誤本身,那麼更單純的 Option 型別可能是更好的選擇)。
沒有發生錯誤時,結果通常是 Right(記憶法:代表正確的那個值),而發生錯誤時則是 Left,例如帶有錯誤訊息的 Left[String]。
請注意,在 Scala 2.12 中,Either預設是偏右的,所以像是filter、map、flatMap這類操作,或是在 for-comprehension 裡,它都能如預期般運作。
如果你不熟悉 Either,可以閱讀這篇教學。但請注意,這篇教學談的是 2.12 之前的 Scala 版本。使用 Scala 2.12 時,你可以放心忽略 RightProjection,並省略 .right。
Either是一種所謂的Monad,涵蓋了某種「運算面向」,在這裡指的就是錯誤處理。
妥善運用 Monad 可以寫出非常簡潔,卻又優雅且易讀的程式碼。運用不當則很容易得到相反的結果。
想進一步了解,請觀看這段影片。
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)
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