Erlang: Why My Integer List Printed as String

Pada halaman 86 (kertas) atau 62 (pdf) di buku Erlang Programming, terdapat kode sebagai berikut:
coba jalankan, dan ternyata hasilnya tidak sesuai dengan harapan:
1> example:even([10,11,12]).
“\n\f”
seharusnya hasilnya adalah [10,12] bukan “\n\f”. Ketik baris kode berikut di Erlang shell:
2> [10,12].
“\n\f”
Hal ini menunjukkan bahwa tidak ada yang salah dengan hasilnya. Erlang menampilkan nilai sebuah list yang berisi integer sebagai string, namun hanya jika semua integer di dalam list adalah integer yang mereprentasikan string. Contoh integer yang tidak mereprentasikan string atau tidak dikonversikan menjadi string adalah 1, 2, 3, 4, 5, 6, dan 7. Bila list anda terdiri dari campuran integer yang menampilkan dan tidak menampilkan string maka list anda tidak akan di konversi. Katakanlah list anda adalah [1,10,12], maka list akan tetap menampilkan nilai [1,10,12] dan bukan “1\n\f”.
Oleh karena itu, saya memodifikasi modul di atas menjadi sebagai berikut. Namun hasilnya adalah sebuah tuple bukan list:
Compile dan jalankan modul yang telah dimodifikasi. Sekarang hasilnya adalah {10, 12} dan bukan “1\n\f”:
3> example:even([10,11,12]).
{10,12}
Jika anda ingin mengkonversi tuple ke list gunakan BIF (built in functions): tuple_to_list().

Pada halaman 86 (kertas) atau 62 (pdf) di buku Erlang Programming, terdapat modul untuk mengambil angka-angka genap dari sebuah list integer sebagai berikut:

-module(example).
-export([even/1]).

even([]) -> [];
even([H|T]) when H rem 2 == 0 -> [H | even(T)];
even([_|T]) -> even(T).

coba jalankan, dan ternyata hasilnya tidak sesuai dengan harapan:

1> example:even([10,11,12]). 
"\n\f"

seharusnya hasilnya adalah [10,12] bukan “\n\f”. Ketik baris kode berikut di Erlang shell:

2> [10,12].
"\n\f"

Hal ini menunjukkan bahwa tidak ada yang salah dengan hasilnya. Erlang menampilkan nilai sebuah list yang berisi integer sebagai string, namun hanya jika semua integer di dalam list adalah integer yang mereprentasikan string. Contoh integer yang tidak mereprentasikan string atau tidak dikonversikan menjadi string adalah 1, 2, 3, 4, 5, 6, dan 7. Bila list anda terdiri dari campuran integer yang menampilkan dan tidak menampilkan string maka list anda tidak akan di konversi. Katakanlah list anda adalah [1,10,12], maka list akan tetap menampilkan nilai [1,10,12] dan bukan “1\n\f”.

Oleh karena itu, saya memodifikasi modul di atas menjadi sebagai berikut. Namun hasilnya adalah sebuah tuple bukan list:

-module(example).
-export([even/1]).

even(L) -> list_to_tuple(get_even(L)).

get_even([]) -> [];
get_even([H|T]) when H rem 2 == 0 -> [H | get_even(T)];
get_even([_|T]) -> get_even(T).

Compile dan jalankan modul yang telah dimodifikasi. Sekarang hasilnya adalah {10, 12} dan bukan “\n\f”:

3> example:even([10,11,12]). 
{10,12}

Jika anda ingin mengkonversi tuple ke list gunakan BIF (built in functions): tuple_to_list().

Erlang Programming, Exercise 2-3: Simple Pattern Matching

Saya sedang membaca buku Erlang Programming. Nah ini adalah solusi dari Exercise 2-3: Simple Pattern Matching. Pertanyaan aslinya adalah sebagai berikut:

Write a module boolean.erl that takes logical expressions and Boolean values (represented as the atoms true and false) and returns their Boolean result. The functions you write should include b_not/1, b_and/2, b_or/2, and b_nand/2. You should not use the logical constructs and, or, and not, but instead use pattern matching to achieve your goal.Test your module from the shell. Some examples of calling the exported functions in your module include:

bool:b_not(false) => true
bool:b_and(false, true) => false
bool:b_and(bool:b_not(bool:b_and(true, false)), true) => true

The notation foo(X) => Y means that calling the function foo with parameter X will result in the value Y being returned. Keep in mind that and, or, and not are reserved words in Erlang, so you must prefix the function names with b_.

Hint: implement b_nand/2 using b_not/1 and b_and/2.

Solusinya adalah:

-module(bool).
-export([b_not/1, b_and/2, b_or/2, b_nand/2]).

b_not(X) -> X == false.
b_and(X,Y) -> {true, true} == {X,Y}.
b_or(X,Y) -> b_not({false, false} == {X,Y}).
b_nand(X,Y) -> b_not(b_and(X,Y)).

Ada yang punya solusi lebih baik?

Erlang: #5 and #6 of 99 Lisp Problems

Di Erlang From 99 Lisp Problems terdapat contoh dasar-dasar kode Erlang, namun tidak ada pembahasan bagaimana cara kerja dari kode-kode tersebut. Pada post ini saya akan membahas problem 5 dan 6. Problem 1 sampai dengan 4 bisa dibaca pada tulisan-tulisan sebelumnya termasuk simbol-simbol yang tidak saya bahas di sini (seperti [H|T], [_|T], dsb).  Problem-problem yang lain akan saya bahas di lain waktu.

Problem 5.a. Reverse List

rev([]) -> [];
rev([H|T]) -> rev(T)++[H].

Input list adalah [a,b,c,d]. Program dijalankan melalui shell dengan perintah: nama_modul:rev([a,b,c,d]). Kali ini diperkenalkan append operator: ++. Contoh penggabungan 2 list menggunakan ++ adalah [1,2] ++ [3,4] = [1,2,3,4]. Cara kerja program di atas secara berurutan adalah sebagai berikut:

Catatan
: Nomor berhuruf ‘a’ menggunakan fungsi rev([]) -> [], sedangkan nomor berhuruf ‘b’ menggunakan fungsi rev([H|T]) -> rev(T)++[H].

1.a. Tidak digunakan karena list tidak kosong.
1.b. rev(a,b,c,d) -> rev(b,c,d) ++ [a] 

2.a. Tidak digunakan karena list tidak kosong.
2.b. rev(b,c,d) -> rev(c,d) ++ [b] ++ [a].

3.a. Tidak digunakan karena list tidak kosong.
3.b. rev(c,d) -> rev(d) ++ [c] ++ [b,a].

4.a. Tidak digunakan karena list tidak kosong.
4.b. rev(d) -> rev([]) ++ [d] ++ [c,b,a].

5.a. rev([]) -> [] ++ [d,c,b,a] -> [d,c,b,a].
5.b. Tidak digunakan karena list kosong.

Sisi kanan yang berhuruf tebal dan berwarna maroon adalah hasil sesungguhnya dari sisi kiri, sedangkan sisanya adalah penggabungan dari hasil sebelumnya.

Problem 5.b. Reverse with Tail Rec

Program ini mempunyai hasil yang sama dengan problem 5.a., hanya melalui pendekatan yang berbeda.

revtail(L) -> revt(L,[]).

revt([],L) -> L;
revt([H|T], L) -> revt(T, [H|L]).

revtail(L) akan memanggil fungsi revt(L,[]). Jadi, yang perlu dibahas adalah fungsi revt/2. Input list adalah [a,b,c,d]. Program dijalankan melalui shell dengan perintah: nama_modul:revtail([a,b,c,d]). Cara kerja program di atas secara berurutan adalah sebagai berikut:

Catatan: Nomor berhuruf ‘a’ menggunakan fungsi revt([],L) -> L, sedangkan nomor berhuruf ‘b’ menggunakan fungsi revt([H|T], L) -> revt(T, [H|L]).

1.a. Tidak cocok. revt([],L) minta argumen 1 kosong,
     sedangkan
argumen 1 dari revt(L,[]) tidak kosong.   
1.b.
revt([a,b,c,d], []) -> revt([b,c,d], [a]). 

2.a. Lihat alasan 1.a.
2.b. 
revt([b,c,d], [a]) -> revt([c,d], [b,a]).

3.a. Lihat alasan 1.a.
3.b. revt([c,d], [b,a]) -> revt([d], [c,b,a]).

4.a. Lihat alasan 1.a.
4.b. revt([d], [c,b,a]) -> revt([], [d,c,b,a]).

5.a. revt([], [d,c,b,a]) -> [d,c,b,a].
5.b. Tidak cocok.

Problem 6. Is Palindrome

Program ini berfungsi untuk menguji bila sebuah list memiliki urutan yang sama baik dibaca dari depan maupun dari belakang.

ispalin(L) -> L =:= revtail(L).

Kali ini diperkenalkan operator =:= yang berguna untuk menguji keidentikan (test of identical).

Program ini memanggil revtail/1 yang telah saya bahas di problem 5.b. yang berfungsi untuk membalik sebuah list. Program dijalankan melalui shell dengan perintah: nama_modul:ispalin(L). dimana L adalah sebuah list. Cara kerja program di atas secara berurutan adalah sebagai berikut dan kali ini saya menggunakan 2 input sebagai perbandingan.

Input = [a,b,c,d] :

ispalin([a,b,c,d]) -> [a,b,c,d] =:= [d,c,b,a] -> false;  

Input = [a,b,b,a] :

ispalin([a,b,b,a]) -> [a,b,b,a] =:= [a,b,b,a] -> true;

Sebagai bonus, mari kita lihat operator-operator dalam Erlang beserta artinya:

Operator:      Artinya:
X > Y          X lebih besar dari Y.
X < Y          X lebih kecil dari Y.
X =< Y         X sama dengan atau lebih kecil dari Y.
X >= Y         X lebih besar dari atau sama dengan Y.
X == Y         X sama dengan Y.
X /= Y         X tidak sama dengan Y.
X =:= Y        X identik dengan Y.
X =/= Y        X tidak identik dengan Y.

Operator =:= mendapat perhatian khusus di sini. Operator =:= mirip dengan == pada bahasa C dan Java, sedangkan programer Delphi akan menggunakan operator =.  Erlang memiliki operator ==, tapi hanya digunakan untuk membandingkan antara nilai float dan integer. Bila ada kode Erlang yang menggunakan == maka harus dicurigai dan diperiksa ulang, bisa jadi tidak menghasilkan error selama tidak melibatkan float, tetapi hampir 99% kode Erlang cenderung menggunakan =:=.

Erlang: #3 and #4 of 99 Lisp Problems

Di Erlang From 99 Lisp Problems terdapat contoh dasar-dasar kode Erlang, namun tidak ada pembahasan bagaimana cara kerja dari kode-kode tersebut. Pada post ini saya akan membahas problem 3 dan problem 4. Problem-problem yang lain akan saya bahas di lain waktu.

Problem 1 dan 2 bisa dilihat di sini. Bila anda mendapati ada simbol-simbol yang tidak saya bahas di sini (seperti [H|T], [_|T], dsb) bisa di baca di tulisan-tulisan saya sebelumnya.

Problem 3. Element at

element_at(L,1) -> hd(L);
element_at([_|T],Pos) -> element_at(T,Pos - 1).

Input list adalah [a,b,c,d], sehingga L = [a,b,c,d]. Kita akan mencari elemen ke-3 dari list tersebut dengan perintah melalui shell nama_modul:element_at(L,3). Urutan list dimulai dari 1 dan bukan 0. Ini ditunjukkan pada fungsi element_at(L,1). hd() adalah built-in function (BIF) untuk mencari kepala (urutan pertama) dari list. Cara kerja program di atas secara berurutan adalah sebagai berikut:

Catatan: urutan angka yang mengandung huruf “a” menggunakan fungsi element_at(L,1) sedangkan “b” menggunakan element_at([_|T],Pos).

1a. tidak digunakan.
1b. element_at([a,b,c,d], 3) -> element_at([b,c,d], 2).

2a. tidak digunakan.
2b. element_at([b,c,d], 2) -> element_at([c,d], 1).

3a. element_at([c,d], 1) -> hd(c,d) -> c.
3b. tidak digunakan.

Problem 4.a. Length list

len([]) -> 0;
len([_|T]) -> 1 + len(T).

Masih menggunakan input L = [a,b,c,d], program dijalankan dengan perintah melalui shell nama_modul:len(L). Cara kerja program di atas secara berurutan adalah sebagai berikut:

Catatan: urutan angka yang mengandung huruf “a” menggunakan fungsi len([]) -> 0 , sedangkan “b” menggunakan len([_|T]) -> 1 + len(T).

1a. tidak digunakan karena input bukan berupa list kosong.
1b. len(a,b,c,d) -> 1 + len(b,c,d]).

2a. tidak digunakan.
2b. 1 + len(b,c,d) -> 1 + 1 + len(c,d) -> 2 + len(c,d)

3a. tidak digunakan.
3b. 2 + len(c,d) -> 2 + 1 + len(d) -> 3 + len(d)

4a. tidak digunakan.
4b. 3 + len(d) -> 3 + 1 + len([]) -> 4 + 0 -> 4.

len(d) hanya mempunyai kepala dan tidak memiliki ekor sehingga ketika menggunakan fungsi len([_|T]) -> 1 + len(T) akan tampak sebagai berikut len(d) -> 1 + len([]) -> 1 + 0 -> 1.

Problem 4.b. Length list with fold

lenf(L) -> lists:foldl(fun(_,Len)-> 1 + Len end, 0, L).

Erlang mempunyai banyak libraries yang terdiri dari modul-modul. Kita akan menggunakan modul lists yang telah disediakan oleh Erlang. Modul lists mempunyai fungsi foldl/3 (fungsi foldl yang memiliki 3 argumen) yang akan digunakan pada contoh program kali ini. Sebelumnya akan saya uraian dulu pemakaian fungsi lists:foldl/3:

lists:foldl/3 mempunyai 3 argumen:

  • foldl/1 (argumen ke-1) diisi dengan fungsi yang memiliki 2 argumen misalnya fun(X,Sum)-> X + Sum.
  • foldl/2 (argumen ke-2) diisi dengan nilai awal untuk argumen ke-2 dari fungsi fun(X,Sum). Kalau nilainya 0 maka fun(X,0).
  • foldl/3 (argumen ke-3) diisi dengan list yang akan diproses mulai dari kiri. Jika ada list [1,2,3,4] maka akan diproses mulai dari angka 1. Sekedar info, pada lists:foldr/3, list akan di proses mulai dari kanan

Sekarang mari kita lihat cara kerja contoh program yang dijalankan melalui shell dengan perintah nama_modul:lenf(L) secara berurutan:

1. lists:foldl(fun(a,0) -> 1 + 0 end, 0, [a,b,c,d]) -> 1
2. lists:foldl(fun(b,1) -> 1 + 1 end, 0, [b,c,d]) -> 2
3. lists:foldl(fun(c,2) -> 1 + 2 end, 0, [c,d]) -> 3
4. lists:foldl(fun(d,3) -> 1 + 3 end, 0, [d]) -> 4

Variabel L dari bentuk [a,b,c,d]menjadi [d]cuma untuk mempermudah pemahaman saja dan tidak berarti variable L berubah elemennya. He…he.. agak ribet. Kalau nggak ada yang protes aku biarin aja deh.

Missed? Make a Dot Prefixed Directory Name

Benar-benar sontoloyo… Cukup lama juga aku mencoba membuat nama direktori di Windows yang ada titik di depannya menggunakan Explorer. Ternyata nggak bisa. Eee.. jebule mesti pake command prompt. Dasar katrok!

makedotdir