Pemrograman deklaratif vs. pemrograman imperatif

24

Saya merasa sangat nyaman dengan pemrograman Imperatif. Saya tidak pernah mengalami kesulitan dalam mengekspresikan algoritme apa yang saya ingin komputer lakukan setelah saya menemukan apa yang ingin saya lakukan. Tetapi ketika datang ke bahasa seperti SQL atau saya sering terjebak karena kepala saya terlalu terbiasa dengan pemrograman Imperatif.

Misalnya, Anda memiliki band hubungan (bandName, bandCountry), venue (venueName, venueCountry), drama (bandName, venueName), dan saya ingin menulis kueri yang mengatakan: semua nama venue sedemikian rupa sehingga untuk setiap bandNegara ada band dari negara yang bermain di tempat nama itu.

Contoh: Saya ingin semua nama venue tempat band dari semua negara (bandCountry) bermain. Juga, dengan "hubungan" yang saya maksud adalah tabel SQL.

Dalam benak saya, saya segera pergi "untuk setiap venueName, ganti semua bandCountries dan untuk setiap bandCountry dapatkan daftar band yang berasal darinya. Jika tidak ada yang bermain di venueName, pergi ke venueName berikutnya. Lain, di akhir bandCountries iteration menambahkan venueName ke set nama venue yang baik ".

... tetapi Anda tidak dapat berbicara seperti itu di SQL dan saya benar-benar perlu memikirkan cara merumuskan ini, dengan solusi Imperatif intuitif yang terus-menerus mengganggu di belakang kepala saya. Apakah ada orang lain yang memiliki masalah ini? Bagaimana Anda mengatasi ini? Apakah Anda menemukan pergeseran paradigma? Membuat peta dari konsep Imperatif ke konsep SQL untuk menerjemahkan solusi Imperatif menjadi solusi Deklaratif? Baca buku yang bagus?

PS Saya tidak mencari solusi untuk pertanyaan di atas, saya menyelesaikannya.

EpsilonVector
sumber
1
Ini adalah pertanyaan yang bagus karena Anda menyuarakan kelemahan yang dimiliki banyak orang (termasuk saya).
David Weiser
Mungkin berguna untuk mendefinisikan apa yang Anda maksud dengan "hubungan" dalam pertanyaan Anda. Dalam model relasional (matematika di balik SQL), "hubungan" kira-kira analog dengan tabel SQL. Banyak orang akan mengatakan "hubungan" ketika mereka benar-benar bermaksud mengatakan "hubungan".
Jason Baker
Belajar teori himpunan, dan matematika diskrit.
1
@ Jase21, saya pribadi cukup akrab dengan keduanya, tetapi hal-hal yang tidak sepele dalam SQL masih terasa lucu. Tidak ada contoh matematika bersih yang berurusan dengan hal-hal dunia nyata yang aneh. Selain itu, seseorang dapat menggunakan LINQ, dan karenanya tidak terganggu dengan SQL. Akhirnya, untuk si penanya: Anda akan terbiasa dengan waktu.
Pekerjaan

Jawaban:

12

Ide di balik melakukan hal-hal secara deklaratif adalah bahwa Anda seharusnya menentukan apa , bukan bagaimana .

Bagi saya, sepertinya Anda berada di jalur yang benar. Masalahnya bukan bahwa Anda memikirkan hal-hal dengan cara yang salah. Itu karena Anda terlalu jauh. Mari kita lihat apa yang Anda coba lakukan:

Misalnya, Anda memiliki band hubungan (bandName, bandCountry), venue (venueName, venueCountry), drama (bandName, venueName), dan saya ingin menulis kueri yang mengatakan: semua nama venue sedemikian rupa sehingga untuk setiap bandNegara ada band dari negara yang bermain di tempat nama itu.

Sejauh ini, ini hebat. Tetapi kemudian Anda melakukan ini:

Dalam benak saya, saya segera pergi "untuk setiap venueName, ganti semua bandCountries dan untuk setiap bandCountry dapatkan daftar band yang berasal darinya. Jika tidak ada yang bermain di venueName, pergi ke venueName berikutnya. Lain, di akhir bandCountries iteration menambahkan venueName ke set nama venue yang baik ".

Intinya, Anda melakukan pekerjaan yang tidak perlu. Anda tahu apa yang Anda inginkan, itulah yang benar-benar Anda butuhkan. Tetapi kemudian Anda melanjutkan dan mencoba mencari cara untuk mendapatkannya.

Jika saya jadi Anda, saya akan mencoba membiasakan diri sebagai berikut:

  1. Tentukan apa yang Anda inginkan.
  2. Secara sadar hentikan diri Anda dari menentukan cara mendapatkannya.
  3. Cari tahu bagaimana cara mewakili apa yang Anda inginkan dalam SQL.

Mungkin butuh waktu dan usaha dari Anda, tetapi begitu Anda benar-benar grok pemrograman deklaratif, itu menjadi sangat berguna. Bahkan, Anda mungkin menemukan diri Anda menggunakan pemrograman deklaratif di sisa kode Anda.

Jika Anda mencari buku, saya akan merekomendasikan SQL dan Teori Relasional . Ini sangat membantu Anda memahami teori di balik database SQL. Ingatlah untuk mengambil rekomendasi Date dengan sebutir garam. Dia memberikan informasi yang sangat bagus, tetapi dia kadang-kadang bisa sedikit berargumen.

Jason Baker
sumber
Saya tidak mengerti bagaimana mencari cara mendapatkan sesuatu adalah pendekatan yang salah. Tidak masalah bahasa apa yang Anda gunakan, Anda harus mencari tahu bagaimana mengatakannya untuk melakukan apa yang Anda inginkan.
davidk01
9

berpikir dalam hal set, bukan iterator; pernyataan sql mendefinisikan properti set output yang diinginkan (alias tabel / relasi)

semua venueNames sedemikian rupa sehingga untuk setiap bandCountry ada band dari negara itu yang bermain di venue nama itu

hasil dari ini (jika saya memahami maksud Anda dengan benar!) akan menjadi himpunan tempat yang memiliki setidaknya satu band yang bermain di tempat itu. Iterasi atas bandCountry tidak perlu, karena relasi PLAYS sudah memiliki informasi yang Anda cari, Anda hanya perlu menghilangkan duplikat

jadi dalam SQL ini akan menjadi:

select 
    distinct venueName
from PLAYS

EDIT: ok, jadi set sebenarnya yang diinginkan sedikit lebih rumit. Pertanyaan yang diajukan dari database adalah: venue apa yang telah menjadi tuan rumah band dari semua negara?

Jadi, kami mendefinisikan kriteria keanggotaan untuk elemen set yang diinginkan sebagai tujuan, lalu bekerja mundur untuk mengisi set. Sebuah venue adalah anggota dari set output jika memiliki baris PLAYS untuk setidaknya satu band dari setiap negara. Bagaimana kami mendapatkan informasi ini?

Salah satu caranya adalah dengan menghitung negara yang berbeda untuk setiap tempat dan membandingkannya dengan jumlah semua negara. Tapi kami tidak memiliki hubungan NEGARA. Jika kita memikirkan model yang diberikan untuk sesaat, kita melihat bahwa himpunan semua negara bukanlah kriteria yang tepat; itu adalah himpunan semua negara yang memiliki setidaknya satu band. Jadi kita tidak memerlukan tabel negara (meskipun untuk model yang dinormalisasi kita harus memilikinya), dan kita tidak peduli dengan negara tempat, kita bisa menghitung negara-negara yang memiliki band, misalnya (dalam MS-SQL )

declare @BandCountryCount int
select
    @BandCountryCount = COUNT(distinct bandCountry)
from BAND

Kami dapat menghitung negara band untuk setiap venue

select
    P.venueName, COUNT(distinct B.bandCountry) as VenueBandCountryCount
from PLAYS P
    inner join BAND B on B.bandName = P.bandName

dan kita bisa menyatukan keduanya menggunakan subquery

select
    venueName
from (
    select
        P.venueName, COUNT(distinct B.bandCountry) as VenueBandCountryCount
    from PLAYS P
        inner join BAND B on B.bandName = P.bandName
) X
where X.VenueBandCountryCount = @BandCountryCount

Sekarang, itu bukan permintaan tercantik yang mungkin (GROUP BY dan HAVING mungkin dianggap solusi yang lebih 'elegan' daripada variabel temp dan subquery) tapi cukup jelas apa yang kita cari sehingga kita akan membiarkannya di situ untuk tujuan OP .

Tujuan OP adalah untuk belajar bagaimana mengubah pola pikir dari imperatif ke deklaratif. Untuk itu, lihat apa yang dilakukan oleh solusi imperatif:

untuk setiap venueName, ulangi semua bandCountries dan untuk setiap bandCountry dapatkan daftar band yang berasal darinya. Jika tidak ada yang bermain di venueName, pergi ke venueName berikutnya. Selain itu, pada akhir pengulangan bandCountries, tambahkan venueName ke set venue venue yang baik

Apa kriteria penentu di atas? Aku rasa ini:

... Jika tidak satupun dari mereka [kelompok band dari negara tertentu] bermain di venueName ...

Ini adalah kriteria yang mendiskualifikasi . Proses berpikir imperatif dimulai dengan ember penuh dan membuang hal-hal yang tidak sesuai dengan kriteria. Kami memfilter data.

Itu bagus untuk hal-hal sederhana, tetapi membantu berpikir dalam hal membangun set hasil yang diinginkan; apa kriteria kualifikasi yang sesuai yang akan memungkinkan seseorang untuk mengisi ember sebagai gantinya?

  • didiskualifikasi: jika tidak ada band dari bandCountry yang bermain di suatu venue, venue tersebut didiskualifikasi
  • kualifikasi (parsial): jika setidaknya satu band dari bandCountry bermain di suatu venue, maka venue tersebut mungkin oke; terus memeriksa sisa bandCountries
  • Kualifikasi (penuh): jika setidaknya satu band dari masing-masing bandCountry bermain di suatu venue, maka venue tersebut memenuhi syarat

Kualifikasi akhir dapat disederhanakan menggunakan hitungan: bandCountry 'puas' jika setidaknya satu band dari sana bermain di suatu venue; jumlah negara band 'puas' untuk suatu venue harus sama dengan jumlah negara band untuk tempat yang akan dikualifikasi.

Sekarang kita dapat memberi alasan lintas hubungan dengan navigasi:

  • mulai dengan relasi VENUE [kita tidak membutuhkannya untuk jawabannya, tetapi ini adalah titik awal konseptual untuk navigasi relasional]
  • bergabunglah dengan PLAYS di venueName
  • bergabunglah dengan BAND di bandName untuk mendapatkan bandCountry
  • kami tidak peduli dengan nama band; pilih hanya venueName dan bandCountry
  • kami tidak peduli tentang band-band yang berlebihan; menghilangkan duplikat menggunakan DISTRICT atau GROUP BY
  • kami hanya peduli tentang jumlah band band berbeda, bukan nama
  • kami hanya ingin tempat di mana jumlah bandCountries berbeda sama dengan jumlah total bandCountries

yang mengarah kembali ke solusi di atas (atau faksimili yang masuk akal)

RINGKASAN

  • teori set
  • jalur navigasi relasional
  • kriteria inklusif vs eksklusif (kualifikasi vs diskualifikasi)
Steven A. Lowe
sumber
Sebenarnya "set venue yang dimainkan band-band dari semua negara (bandCountry> = venueCountry)".
EpsilonVector
@EpsilonVector: lihat suntingan
Steven A. Lowe
4

Salah satu cara untuk mempelajari cara berpikir dan memprogram dalam gaya deklaratif adalah dengan mempelajari bahasa susunan tujuan umum seperti APL atau J. SQL mungkin bukan kendaraan terbaik untuk mempelajari cara memprogram deklaratif. Di APL atau J Anda belajar untuk beroperasi pada seluruh array (vektor, matriks, atau array dengan peringkat lebih tinggi), tanpa pengulangan atau pengulangan yang eksplisit. Ini membuat pemahaman SQL dan aljabar relasional jauh lebih mudah. Sebagai contoh yang sangat sederhana, untuk memilih item dari vektor V yang nilainya lebih besar dari 100, dalam APL kita menulis:

(V>100)/V

Di sini V> 100 mengevaluasi ke array boolean dengan bentuk yang sama dengan V, dengan 1 menandai nilai yang ingin kita pertahankan. Tidak terjadi pada APLer berpengalaman bahwa ada iterasi yang terjadi, kami hanya menerapkan masker ke vektor V, mengembalikan vektor baru. Ini tentu saja secara konseptual apa SQL di mana klausa atau aljabar relasional membatasi operasi lakukan.

Saya tidak berpikir Anda bisa menguasai pemrograman deklaratif tanpa melakukan banyak hal, dan SQL umumnya terlalu spesifik. Anda perlu menulis banyak kode tujuan umum, belajar bagaimana melakukannya tanpa loop dan jika / kemudian / lain struktur dan semua peralatan yang menghadiri pemrograman gaya imperatif, prosedural dan skalar.

Mungkin ada bahasa fungsional lain yang membantu dengan cara berpikir ini juga, tetapi bahasa array sangat dekat dengan SQL.

PAUL Mansour
sumber
+1 untuk "[Anda tidak bisa] mendapatkan pegangan yang baik ... tanpa melakukan banyak hal". Tidak ada yang belajar pemrograman imperatif (dengan konstruk yang jelas kontra-intuitif seperti a = a + 1) semalam. Dibutuhkan waktu untuk mempelajari gaya deklaratif seperti logika, fungsional, dan lain-lain seperti butuh waktu untuk mempelajari pemrograman imperatif.
HANYA SAYA PENDAPAT benar
1

Pertama, Anda harus mempelajari keduanya. Anda mungkin memiliki preferensi, tetapi ketika bekerja di daerah di mana yang lain lebih baik, jangan melawannya. Banyak programmer yang tergoda untuk menggunakan kursor dalam database relasional karena mereka sangat terbiasa untuk melangkah melalui setiap record, tetapi database jauh lebih baik di set. Anda tidak ingin masuk ke dalam pola pikir "Saya tahu bagaimana melakukannya dengan cara ini dan saya memiliki kendali paling besar, bla, bla, bla".

JeffO
sumber
1

Anda belajar berpikir secara deklaratif seperti Anda belajar berpikir secara imperatif: dengan berlatih mulai dengan masalah yang lebih sederhana dan terus maju saat Anda "mengerti".

Pengalaman pertama Anda dengan pemrograman imperatif mencakup sejumlah pernyataan kontra-intuitif (dan, pada kenyataannya, sangat konyol) seperti " a = a + 1". Anda memusatkan pikiran Anda ke titik yang sekarang Anda mungkin bahkan tidak ingat mundur dari ketidakbenaran jelas dari pernyataan itu. Masalah Anda dengan gaya deklaratif adalah bahwa Anda kembali ke tempat Anda berada saat pertama kali memulai dengan gaya imperatif: a "clueless newb". Lebih buruk lagi, Anda sudah bertahun-tahun berlatih dengan satu gaya yang benar-benar bertentangan dengan gaya baru ini dan memiliki kebiasaan bertahun-tahun untuk dibatalkan - seperti kebiasaan untuk "mengendalikan dengan segala cara".

Gaya deklaratif bekerja dengan pendekatan berbeda yang Anda tidak memiliki intuisi untuk saat ini (kecuali jika Anda telah menjaga keterampilan matematika Anda sangat tajam selama bertahun-tahun - yang kebanyakan orang tidak). Anda harus mempelajari kembali cara berpikir dan satu-satunya cara untuk mempelajari kembali itu adalah dengan melakukannya, satu langkah sederhana pada suatu waktu.

Memilih SQL sebagai perampokan pertama Anda ke pemrograman deklaratif mungkin merupakan kesalahan jika Anda benar-benar ingin mempelajari konsep-konsepnya. Tentu kalkulus tuple yang menjadi dasarnya adalah deklaratif, tetapi sayangnya kemurnian kalkulus tuple telah sangat dikompromikan oleh realitas implementasi dan bahasa tersebut, pada dasarnya, telah menjadi sedikit berantakan. Sebagai gantinya, Anda mungkin ingin melihat bahasa lain yang lebih langsung berguna (dalam arti Anda terbiasa) bahasa deklaratif seperti Lisps (esp. Scheme ), Haskell dan ML untuk (kebanyakan) pemrograman fungsional atau, sebagai alternatif, Prolog dan Merkurius untuk (kebanyakan) pemrograman logika.

Mempelajari bahasa-bahasa lain ini akan memberi Anda wawasan yang lebih baik, menurut pendapat saya, tentang bagaimana pemrograman deklaratif bekerja karena beberapa alasan:

  1. Mereka berguna untuk pemrograman "cradle to grave" - ​​karena Anda dapat menulis program lengkap dalam bahasa-bahasa ini dari awal hingga akhir. Mereka berguna berdiri sendiri, tidak seperti SQL yang benar-benar sangat tidak berguna bagi kebanyakan orang sebagai bahasa mandiri.

  2. Mereka masing-masing memberi Anda pandangan yang berbeda pada pemrograman deklaratif yang dapat memberi Anda jalan yang berbeda untuk akhirnya "mendapatkannya".

  3. Mereka juga masing-masing memberi Anda pandangan yang berbeda pada pemikiran tentang pemrograman secara umum. Mereka akan meningkatkan kemampuan Anda untuk beralasan tentang masalah dan pengkodean meskipun Anda tidak pernah menggunakannya secara langsung.

  4. Pelajaran yang Anda pelajari dari mereka akan membantu Anda dengan SQL Anda juga - terutama jika Anda memoles kalkulus tuple di belakang database relasional untuk bentuk murni berpikir tentang data.

Saya terutama merekomendasikan belajar salah satu bahasa fungsional ( Clojure , sebagai salah satu Lisps, mungkin merupakan pilihan yang baik di sini) dan salah satu bahasa logika (saya suka merkuri terbaik, tetapi Prolog memiliki banyak bahan yang lebih berguna untuk belajar) untuk perluasan proses berpikir maksimal.

HANYA PENDAPAT SAYA yang benar
sumber
1

Tidak salah untuk berpikir secara imperatif dalam pengaturan deklaratif seperti SQL. Hanya saja, pemikiran imperatif harus terjadi pada tingkat yang sedikit lebih tinggi dari apa yang Anda gambarkan. Setiap kali saya perlu query database yang menggunakan SQL saya selalu berpikir sendiri:

  • Inilah bagian yang saya butuhkan.
  • Saya akan menggabungkan mereka dengan cara ini.
  • Saya akan mengurangi apa yang baru saja saya dapatkan dengan predikat berikut untuk mendapatkan apa yang sebenarnya saya cari.

Di atas adalah algoritma imperatif tingkat tinggi dan berfungsi cukup baik bagi saya dalam pengaturan SQL. Saya pikir ini dianggap sebagai pendekatan top-down dan Steven A. Lowe menggambarkan pendekatan bottom-up yang cukup bagus .

davidk01
sumber
1

Kunci dari pertanyaan Anda adalah dalam apa yang Anda katakan di paragraf berikutnya hingga terakhir: "Anda tidak dapat berbicara seperti itu di SQL." Mungkin lebih bermanfaat bagi Anda pada tahap ini untuk mendekati SQL sebagai bahasa asing daripada bahasa pemrograman. Jika Anda memikirkannya seperti ini, menulis kueri SQL benar-benar menerjemahkan pernyataan bahasa Inggris tentang apa yang Anda inginkan ke dalam "SQLish". Komputer memahami SQLish dengan sempurna dan akan melakukan apa yang Anda katakan, sehingga Anda tidak perlu khawatir tentang implementasi selama Anda menerjemahkan dengan benar.

Yang mengatakan, apa cara terbaik untuk belajar bahasa asing? Anda jelas harus mempelajari tata bahasa dan kosakata, yang bisa Anda dapatkan dari dokumentasi SQL Anda. Yang paling penting adalah latihan. Anda harus membaca dan menulis SQL sebanyak yang Anda bisa, dan jangan merasa bahwa Anda harus mengetahui sintaks secara menyeluruh terlebih dahulu; Anda dapat, dan harus, mencari hal-hal saat Anda pergi bersama. Anda akan tahu bahwa Anda mendapatkannya ketika Anda merasa lebih mudah untuk menggambarkan data apa yang Anda inginkan dalam SQL daripada dalam bahasa Inggris.

Larry Coleman
sumber
1

Butuh waktu lama untuk membungkus kepala saya di sekitar SQL juga. Kami melakukan beberapa teori relasional di universitas dan pada saat itu, yang hanya mempersulit masalah. Pada akhirnya, proses pembelajaran saya adalah banyak trial and error yang diinformasikan oleh berbagai bahan pembelajaran dan contoh yang saya temukan berguna di sepanjang jalan. Pada dasarnya, Anda akan terbiasa pada akhirnya, dan menambahkan cara berpikir baru tentang data dan pertanyaan akan bermanfaat bagi perkembangan mental Anda.

Saya menemukan bahwa saya dapat mempercepat pembelajaran saya dengan secara bertahap membangun kumpulan skrip sederhana yang menunjukkan bagaimana menggunakan setiap fitur bahasa dan bagaimana mencapai hasil tertentu pada tabel yang diketahui (definisi tabel termasuk untuk referensi).

Awal tahun ini saya melakukan beberapa pelatihan formal yang melibatkan proyek migrasi data pada database Oracle yang berantakan, di mana saya harus secara bertahap mengumpulkan fragmen-fragmen dari perpustakaan saya untuk menyaring hasil kueri dengan berbagai cara sampai saya mendapatkan apa yang saya inginkan, kemudian mengubahnya sebagai perlu, dan sebagainya. Beberapa pertanyaan menjadi sangat kompleks dan sulit untuk di-debug. Saya ragu saya bisa membacanya sekarang, tetapi saya harap saya bisa menemukan solusi yang sama lagi dengan menggunakan blok bangunan referensi saya.

Cara lain untuk meningkatkan kesadaran intuitif Anda tentang ruang deklaratif dan fungsional adalah mempelajari teori himpunan dan bahasa pemrograman yang lebih cocok dengan paradigma tertentu. Saat ini saya sedang dalam proses belajar beberapa Haskell, misalnya, untuk mempertahankan dan meningkatkan kemampuan matematika saya.

IanGilham
sumber
0

Ketika Anda menghadapi masalah Anda biasanya berpikir bagaimana menyelesaikannya. Tetapi jika Anda tahu bagaimana komputer menyelesaikannya untuk Anda! Maka Anda khawatir tentang bagaimana akan dihilangkan.

Saya mencoba mengatakan bagaimana itu terjadi.

Anda mungkin sudah terbiasa dengan program rekursif, dalam program rekursif, Anda mendefinisikan masalahnya daripada mengatakan bagaimana itu diselesaikan. Anda mendefinisikan basis, dan mendefinisikan n berdasarkan pada n-1 . (misalnya factorial(n) = n * factorial(n-1)) Tetapi Anda mungkin sudah tahu bagaimana komputer menyelesaikannya. itu mulai dari fungsi dan memanggil fungsi secara rekursif sampai mencapai definisi dasar, kemudian mengevaluasi semua fungsi lain berdasarkan nilai dasar.

Itulah yang terjadi dalam pemrograman deklaratif. Anda mendefinisikan semuanya berdasarkan definisi yang ada. Dan komputer tahu cara memperoleh jawaban untuk Anda berdasarkan fungsi dasar.

Dalam SQL Anda mungkin tidak menghubungkan definisi satu sama lain tetapi Anda menghubungkan objek atau informasi satu sama lain, Anda menentukan apa yang Anda inginkan dan pencarian komputer untuk sesuatu (objek, informasi) berdasarkan pada hubungan yang Anda berikan.

Ahmad
sumber