當你遞迴走訪可列舉的資料(陣列、位元字串、字串)時,通常會遇到兩個問題:
為了處理這些問題,可以使用_累加器_。
累加器是伴隨資料一起傳遞的變數。它用來在每次函式呼叫之間傳遞函式執行當下的狀態,直到抵達_基本情況_。在基本情況中,累加器會用來回傳遞迴函式呼叫的最終值。
累加器應該由函式的作者初始化,而不是由函式的使用者。為了做到這點,請宣告兩個函式:一個公開函式,只接收必要的資料作為引數,並負責初始化累加器;以及一個私有函式,它也接收累加器。在 Elixir 中,常見的慣例是在私有函式的名稱前面加上do_。
# Count the length of a list without an accumulator
def count([]), do: 0
def count([_head | tail]), do: 1 + count(tail)
# Count the length of a list with an accumulator
def count(list), do: do_count(list, 0)
defp do_count([], count), do: count
defp do_count([_head | tail], count), do: do_count(tail, count + 1)
使用累加器讓我們能把遞迴函式轉換成_尾遞迴_函式。如果一個函式最後執行的事情是呼叫自己,它就是尾遞迴。
在你的 DNA 研究實驗室裡,你一直在嘗試各種壓縮研究資料的方法,好節省儲存空間。一位隊友建議把 DNA 資料轉成二進位表示法:
| 核酸 | 編碼 |
|---|---|
| 空格 | 0000 |
| A | 0001 |
| C | 0010 |
| G | 0100 |
| T | 1000 |
你思索著這件事:這有可能讓所需的資料儲存成本減半,但代價是犧牲了人類可讀性。於是你決定寫一個模組來編碼與解碼資料,好評估自己究竟省下了多少。
實作 encode_nucleotide/1,讓它接受核酸的碼點,並回傳編碼後代碼的整數值。
DNA.encode_nucleotide(?A)
# => 1
# (which is equal to 0b0001)
實作 decode_nucleotide/1,讓它接受編碼後代碼的整數值,並回傳核酸的碼點。
DNA.decode_nucleotide(0b0001)
# => 65
# (which is equal to ?A)
實作 encode/1,讓它接受代表核酸與空隙的字元列表,並回傳編碼後資料的位元字串。
DNA.encode(~c"AC GT")
# => <<18, 4, 8::size(4)>>
實作 decode/1,讓它接受代表核酸與空隙的位元字串,並以字元列表回傳解碼後的資料。
DNA.decode(<<132, 2, 1::size(4)>>)
# => ~c"TG CA"