Pertanyaan Mathematica: apa itu pemrograman simbolis?


Saya adalah penggemar berat Stephen Wolfram, tetapi dia pasti tidak pemalu dengan tanduknya sendiri. Dalam banyak referensi, ia memuji Mathematica sebagai paradigma pemrograman simbolis yang berbeda. Saya bukan pengguna Mathematica.

Pertanyaan saya adalah: apakah pemrograman simbolik ini? Dan bagaimana cara membandingkannya dengan bahasa fungsional (seperti Haskell)?


76
2017-12-13 16:28


asal


Jawaban:


Anda dapat menganggap pemrograman simbolik Mathematica sebagai sistem pencarian-dan-ganti di mana Anda memprogram dengan menentukan aturan pencarian dan ganti.

Misalnya Anda bisa menentukan aturan berikut

area := Pi*radius^2;

Lain kali Anda gunakan area, itu akan diganti dengan Pi*radius^2. Sekarang, anggaplah Anda mendefinisikan aturan baru

radius:=5

Sekarang, kapan pun Anda gunakan radius, itu akan ditulis ulang 5. Jika Anda mengevaluasi area itu akan ditulis ulang Pi*radius^2 yang memicu aturan penulisan ulang untuk radius dan kamu akan mendapatkannya Pi*5^2 sebagai hasil antara. Formulir baru ini akan memicu aturan penulisan ulang untuk ^ operasi sehingga ekspresi akan semakin ditulis ulang menjadi Pi*25. Pada titik ini menulis ulang berhenti karena tidak ada aturan yang berlaku.

Anda dapat meniru pemrograman fungsional dengan menggunakan aturan penggantian Anda sebagai fungsi. Misalnya, jika Anda ingin mendefinisikan fungsi yang ditambahkan, Anda bisa melakukannya

add[a_,b_]:=a+b

Sekarang add[x,y] ditulis ulang menjadi x+y. Jika Anda ingin menambahkan hanya berlaku untuk angka a, b, Anda bisa melakukannya

add[a_?NumericQ, b_?NumericQ] := a + b

Sekarang, add[2,3] ditulis ulang menjadi 2+3 menggunakan aturan Anda dan kemudian ke dalam 5 menggunakan aturan bawaan untuk +, sedangkan add[test1,test2] tetap tidak berubah.

Berikut ini contoh aturan penggantian interaktif

a := ChoiceDialog["Pick one", {1, 2, 3, 4}]
a+1

Sini, a diganti dengan ChoiceDialog, yang kemudian akan diganti dengan nomor yang dipilih pengguna pada dialog yang muncul, yang membuat kedua jumlah numerik dan memicu aturan penggantian untuk +. Sini, ChoiceDialog sebagai aturan penggantian built-in sepanjang baris "ganti ChoiceDialog [beberapa barang] dengan nilai tombol yang diklik pengguna".

Aturan dapat didefinisikan menggunakan kondisi yang perlu melalui penulisan aturan penulisan untuk menghasilkan True atau False. Sebagai contoh misalkan Anda menemukan metode penyelesaian persamaan baru, tetapi Anda pikir itu hanya bekerja ketika hasil akhir dari metode Anda positif. Anda bisa melakukan aturan berikut

 solve[x + 5 == b_] := (result = b - 5; result /; result > 0)

Sini, solve[x+5==20] diganti dengan 15, tapi solve[x + 5 == -20] tidak berubah karena tidak ada aturan yang berlaku. Kondisi yang mencegah penerapan aturan ini /;result>0. Evaluator pada dasarnya melihat potensi output dari aplikasi aturan untuk memutuskan apakah akan melanjutkan dengan itu.

Penilai Mathematica dengan rakus menulis ulang setiap pola dengan salah satu aturan yang berlaku untuk simbol itu. Terkadang Anda ingin memiliki kontrol yang lebih baik, dan dalam hal ini Anda dapat menentukan aturan Anda sendiri dan menerapkannya secara manual seperti ini

myrules={area->Pi radius^2,radius->5}
area//.myrules

Ini akan menerapkan aturan yang didefinisikan dalam myrules sampai hasil berhenti berubah. Ini sangat mirip dengan evaluator default, tetapi sekarang Anda bisa memiliki beberapa set aturan dan menerapkannya secara selektif. Yang lebih maju contoh menunjukkan cara membuat evaluator Prolog-seperti yang mencari lebih dari urutan aplikasi aturan.

Satu kelemahan dari versi Mathematica saat ini muncul ketika Anda perlu menggunakan evaluator default Mathematica (untuk memanfaatkan Integrate, Solve, dll.) dan ingin mengubah urutan evaluasi default. Itu mungkin tapi rumit, dan saya suka berpikir bahwa beberapa implementasi program simbolik di masa depan akan memiliki cara yang lebih elegan untuk mengendalikan urutan evaluasi


70
2017-12-13 22:12



Ketika saya mendengar frase "pemrograman simbolik", LISP, Prolog dan (ya) Mathematica segera melompat ke pikiran. Saya akan mencirikan lingkungan pemrograman simbolis sebagai salah satu di mana ekspresi yang digunakan untuk mewakili teks program juga terjadi menjadi struktur data primer. Akibatnya, menjadi sangat mudah untuk membangun abstraksi pada abstraksi karena data dapat dengan mudah diubah menjadi kode dan sebaliknya.

Mathematica sangat mengeksploitasi kemampuan ini. Bahkan lebih berat dari LISP dan Prolog (IMHO).

Sebagai contoh pemrograman simbolis, pertimbangkan urutan peristiwa berikut. Saya memiliki file CSV yang terlihat seperti ini:

r,1,2
g,3,4

Saya membaca file itu di:

Import["somefile.csv"]
--> {{r,1,2},{g,3,4}}

Apakah data hasil atau kode? Itu keduanya. Ini adalah data yang dihasilkan dari membaca file, tetapi itu juga merupakan ekspresi yang akan membangun data tersebut. Namun, seiring berjalannya kode, ungkapan ini lamban karena hasil evaluasi itu sendiri.

Jadi sekarang saya menerapkan transformasi ke hasil:

% /. {c_, x_, y_} :> {c, Disk[{x, y}]}
--> {{r,Disk[{1,2}]},{g,Disk[{3,4}]}}

Tanpa memikirkan detailnya, semua yang terjadi adalah itu Disk[{...}] telah melilit dua angka terakhir dari setiap baris masukan. Hasilnya masih data / kode, tapi masih lembam. Transformasi lain:

% /. {"r" -> Red, "g" -> Green}
--> {{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}

Ya, masih lembam. Namun, dengan kebetulan yang luar biasa, hasil terakhir ini hanya menjadi daftar arahan valid dalam bahasa khusus domain Mathematica untuk grafis. Satu transformasi terakhir, dan hal-hal mulai terjadi:

% /. x_ :> Graphics[x]
--> Graphics[{{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}]

Sebenarnya, Anda tidak akan melihat hasil terakhir itu. Dalam tampilan epik gula sintaksis, Mathematica akan menunjukkan gambar lingkaran merah dan hijau ini:

alt text

Tetapi kesenangan tidak berhenti di situ. Di bawah semua gula sintaksis kita masih memiliki ekspresi simbolis. Saya dapat menerapkan aturan transformasi lain:

% /. Red -> Black

alt text

Presto! Lingkaran merah menjadi hitam.

Ini adalah semacam "dorongan simbol" yang mencirikan pemrograman simbolik. Sebagian besar pemrograman Mathematica adalah dari alam ini.

Fungsional vs. Simbolik

Saya tidak akan membahas perbedaan antara pemrograman simbolik dan fungsional secara detail, tetapi saya akan menyumbangkan sedikit komentar.

Seseorang dapat melihat pemrograman simbolis sebagai jawaban atas pertanyaan: "Apa yang akan terjadi jika saya mencoba memodelkan semuanya hanya dengan menggunakan transformasi ekspresi?" Pemrograman fungsional, sebaliknya, dapat dilihat sebagai jawaban untuk: "Apa yang akan terjadi jika saya mencoba memodelkan semuanya hanya dengan menggunakan fungsi?" Sama seperti pemrograman simbolik, pemrograman fungsional membuatnya mudah untuk dengan cepat membangun lapisan abstraksi. Contoh yang saya berikan di sini dapat dengan mudah direproduksi, katakanlah, Haskell menggunakan pendekatan animasi reaktif fungsional. Pemrograman fungsional adalah semua tentang komposisi fungsi, fungsi tingkat yang lebih tinggi, kombinatorik - semua hal-hal bagus yang dapat Anda lakukan dengan fungsi-fungsi.

Mathematica jelas dioptimalkan untuk pemrograman simbolik. Adalah mungkin untuk menulis kode dalam gaya fungsional, tetapi fitur fungsional dalam Mathematica benar-benar hanya lapisan tipis di atas transformasi (dan abstraksi bocor pada saat itu, lihat catatan kaki di bawah).

Haskell jelas dioptimalkan untuk pemrograman fungsional. Adalah mungkin untuk menulis kode dalam gaya simbolik, tetapi saya akan berdalih bahwa sintaksis representasi program dan data cukup berbeda, membuat pengalaman menjadi kurang optimal.

Catatan Penutup

Sebagai kesimpulan, saya menganjurkan bahwa ada perbedaan antara pemrograman fungsional (seperti dicontohkan oleh Haskell) dan pemrograman simbolik (seperti dicontohkan oleh Mathematica). Saya pikir bahwa jika seseorang mempelajari keduanya, maka seseorang akan belajar secara substansial lebih dari sekadar mempelajari satu - ujian akhir dari perbedaan.


Leaky Functional Abstraction dalam Mathematica?

Yup, bocor. Coba ini, misalnya:

f[x_] := g[Function[a, x]];
g[fn_] := Module[{h}, h[a_] := fn[a]; h[0]];
f[999]

Benar-benar dilaporkan, dan diakui oleh, WRI. Tanggapan: hindari penggunaan Function[var, body] (Function[body] baik-baik saja).


72
2017-12-14 03:54



Seperti yang telah disebutkan di sini, Mathematica melakukan banyak penulisan ulang istilah. Mungkin Haskell bukanlah perbandingan terbaik, tapi Murni adalah bahasa penulisan ulang fungsional yang bagus (yang seharusnya terasa akrab bagi orang-orang dengan latar belakang Haskell). Mungkin membaca halaman Wiki mereka tentang menulis ulang jangka panjang akan menjernihkan beberapa hal untuk Anda:

http://code.google.com/p/pure-lang/wiki/Rewriting


9
2017-12-14 09:37



Mathematica menggunakan istilah menulis ulang dengan berat. Bahasa menyediakan sintaks khusus untuk berbagai bentuk penulisan ulang, dukungan khusus untuk aturan dan strategi. Paradigma ini bukan "baru" dan tentu saja itu tidak unik, tetapi mereka benar-benar berada di tepi pendarahan dari "pemrograman simbolik" ini, bersama dengan pemain kuat lainnya seperti Aksioma.

Sebagai perbandingan dengan Haskell, yah, Anda bisa menulis ulang di sana, dengan sedikit bantuan dari memo perpustakaan boilerplate Anda, tetapi itu tidak semudah dalam Mathematica yang diketik secara dinamis.


5
2017-12-13 18:23