Tuple dan list

Tuple sebagai struktur berukuran tetap dan list sebagai senarai bertaut beserta operasinya.

Daftar isi

Topik ini merinci dua struktur data inti Erlang yang paling sering dipakai, yaitu tuple sebagai paket nilai berukuran tetap dan list sebagai senarai bertaut. Pembahasan mencakup fungsi akses elemen, penyusunan cons cell, penggabungan list, dan fakta bahwa string adalah list. Semua contoh dievaluasi nyata di shell OTP 29.

Tuple: paket berukuran tetap#

Tuple mengelompokkan sejumlah nilai tetap menjadi satu, ditulis di antara kurung kurawal. Ukuran tuple ditetapkan saat dibuat dan tidak berubah, sehingga tuple tepat untuk data yang bentuknya memang baku, misalnya satu titik waktu dengan tiga komponen:

erlang Membaca dan memodifikasi tuple
Erlang/OTP 29 [erts-17.1.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns]

Eshell V17.1.1 (press Ctrl+G to abort, type help(). for help)
1> T = {2024, 11, 3}.
{2024,11,3}
2> element(1, T).
2024
3> size(T).
3
4> setelement(2, T, x).
{2024,x,3}

Fungsi element/2 membaca elemen pada posisi tertentu dengan indeks mulai dari 1, berbeda dengan kebiasaan nol pada banyak bahasa lain. Fungsi size/1 menghitung jumlah elemennya, dan setelement/3 mengembalikan tuple baru dengan satu posisi diganti. Tuple asli T tetap utuh karena data tidak pernah diubah di tempat. Untuk tuple, bentuk khusus tuple_size/1 lebih dipilih daripada size/1 karena maksudnya lebih jelas bagi pembaca dan bagi compiler.

List dan cons cell#

List adalah senarai bertaut yang panjangnya bebas, ditulis di antara kurung siku. Elemen pertama disebut kepala dan sisanya ekor. Fungsi hd/1 dan tl/1 membaca keduanya, sementara length/1 menghitung seluruh elemen dan lists:seq/2 membuat rentang angka:

erlang Operasi dasar list
5> L = [1, 2, 3].
[1,2,3]
6> hd(L).
1
7> tl(L).
[2,3]
8> length(L).
3
9> [1, 2] ++ [3].
[1,2,3]
10> lists:seq(1, 5).
[1,2,3,4,5]

Operator ++ menyambungkan dua list dan akan dijumpai lagi pada topik rekursi. Struktur sebenarnya di balik notasi tersebut adalah cons cell, yaitu pasangan kepala dan ekor yang dirantai hingga berakhir di list kosong []. Notasi panjang berikut menuliskannya secara eksplisit dan menghasilkan list yang sama:

erlang Notasi cons cell penuh
11> [1 | [2 | [3 | []]]].
[1,2,3]
12> [1 | 2].
[1|2]

Baris ke-12 menaruh bilangan 2 pada posisi ekor, dan hasilnya bukan list sah melainkan list tidak wajar (improper list) yang dicetak berbeda sebagai [1|2]. Notasi [K | S] memang sah untuk membangun atau menguraikan, tetapi ekornya harus tetap berupa list agar hasilnya sah. Kesalahan ini jarang disengaja dan berbahaya karena baru terlihat saat list diproses fungsi umum seperti length/1.

String adalah list#

String pada Erlang bukan tipe tersendiri, melainkan list berisi kode titik unicode. Kesetaraan itu bisa dibuktikan langsung di shell:

erlang Kesetaraan string dan list
13> "abc" =:= [97, 98, 99].
true

Operator =:= membandingkan tipe dan nilai sekaligus, dan hasilnya true menegaskan bahwa "abc" memang sama dengan list [97, 98, 99]. Konsekuensinya, fungsi list seperti length/1 bekerja pada string, dan penggabungan string memakai ++ karena string memang list. Implikasi lebih lanjut, termasuk penanganan unicode dan alternatif berupa binary, dibahas lengkap pada modul Record dan string.

Memilih antara tuple dan list#

Keduanya menyimpan banyak nilai, tetapi kegunaannya berbeda. Tuple mendefinisikan bentuk: jumlah posisinya tetap dan tiap posisi punya makna tetap, sehingga cocok untuk kelompok nilai yang selalu lengkap bersama, misalnya titik waktu {2024, 11, 3} atau data bertanda {suhu, 27}. Bentuk bertanda itulah yang menjadi dasar record pada modul Record dan string. List mendefinisikan kumpulan: isinya boleh berkembang dan diproses satu per satu, sehingga cocok untuk kumpulan item sejenis seperti hasil pembacaan berkas atau antrean pesan. Keliru memilih biasanya terasa dari bentuk kodenya: tuple yang isinya berjumlah banyak dan sering disambung menandakan seharusnya list, sedangkan list yang selalu diuraikan posisi demi posisi menandakan seharusnya tuple.

Utilitas list dari modul lists#

Modul lists menyediakan utilitas yang akan dipakai terus sepanjang jalur ini. Tiga bentuk yang berguna sejak awal adalah penghitungan jumlah elemen tuple, pembacaan posisi tertentu, dan pembalikan urutan:

erlang Utilitas dasar modul lists
1> tuple_size({a, b, c}).
3
2> lists:nth(2, [10, 20, 30]).
20
3> lists:reverse([1, 2, 3]).
[3,2,1]

lists:nth/2 membaca elemen pada posisi tertentu dan memicu error bila posisinya di luar rentang, sedangkan lists:reverse/1 membalikkan urutan seluruh elemen. Pembalikan mungkin terlihat sepele, tetapi idiom rekursi pada modul Rekursi dan list memakainya sebagai langkah penutup yang lazim. Utilitas selanjutnya seperti map, filter, dan foldl memakai fungsi sebagai argumen dan dibahas lengkap pada modul tersebut.

Kesalahan umum#

  • Membaca elemen dengan indeks nol. Indeks tuple mulai dari 1, sehingga element(0, T) memicu error bad argument dengan catatan posisi di luar rentang. Kebiasaan nol dari bahasa lain adalah penyebab yang paling sering.
  • Membaca kepala list kosong. Fungsi hd/1 menuntut list tidak kosong dan tl/1 menuntut list berisi minimal satu elemen. Keduanya memicu error bad argument bila dilanggar:
erlang Error pada akses di luar batas
1> element(0, {a, b}).
** exception error: bad argument
     in function  element/2
        called as element(0,{a,b})
        *** argument 1: out of range
2> hd([]).
** exception error: bad argument
     in function  hd/1
        called as hd([])
        *** argument 1: not a nonempty list
  • Menyambungkan nilai bukan list dengan ++. Operator itu menuntut kedua sisi berupa list, dan satu elemen tunggal perlu dibungkus list terlebih dahulu, misalnya [1] ++ L bukan 1 ++ L.

Cara aman untuk keduanya adalah memeriksa bentuk sebelum membaca: fungsi length/1 untuk menguji list tidak kosong, atau pencocokan pola [K | S] yang sekaligus menuntut bentuknya benar.

Ringkasan#

  • Tuple adalah paket nilai berukuran tetap dengan akses element/2 berindeks mulai dari 1, dan setelement/3 mengembalikan tuple baru.
  • tuple_size/1 lebih dipilih daripada size/1 untuk tuple karena maksudnya lebih jelas.
  • Tuple bertanda {suhu, 27} adalah idiom data terstruktur yang menjadi dasar record pada modul Record dan string.
  • List adalah senarai bertaut dengan hd/1, tl/1, length/1, dan lists:seq/2 sebagai operasi dasarnya.
  • Struktur list adalah cons cell [Kepala | Ekor] hingga list kosong, dan ekor selain list menghasilkan improper list seperti [1|2].
  • String adalah list kode titik unicode, dibuktikan dengan “abc” =:= [97, 98, 99] bernilai true.
  • Tuple untuk bentuk tetap, list untuk kumpulan yang panjangnya bebas.

Referensi#