Baru-baru ini, saya menemukan masalah yang mengharuskan saya untuk mendefinisikan operator "OR" yang logis secara terprogram, tetapi tanpa menggunakan operator itu sendiri.
Yang saya pikirkan adalah ini:
OR(arg1, arg2)
if arg1 = True and arg2 = True
return True
else if arg1 = True and arg2 = False
return True
else if arg1 = False and arg2 = True
return True
else:
return False
Apakah logika ini benar, atau apakah saya melewatkan sesuatu?
programming-logic
logicNoob
sumber
sumber
return arg1 ? arg1 : arg2;
or
operator.Jawaban:
Saya akan mengatakan itu benar, tetapi tidak bisakah Anda memadatkannya menjadi sesuatu seperti ini?
Karena Anda melakukan atau membandingkan, saya tidak berpikir Anda benar-benar perlu memeriksa kombinasi. Itu penting jika salah satu dari mereka benar untuk mengembalikan yang benar. Kalau tidak, kami ingin mengembalikan false.
Jika Anda mencari versi yang lebih pendek yang kurang bertele-tele, ini juga akan berfungsi:
sumber
if arg2 == true
).or(a, b): a ? a : b
Berikut adalah solusi tanpa atau, dan, bukan, perbandingan dan literal boolean:
Mungkin tidak menjadi jauh lebih mendasar daripada itu;)
sumber
true
ataufalse
.||
Singkatnya operator JavaScript (bila diterapkan dalam bahasa yang diketik secara dinamis).Satu baris kode:
Tanpa percabangan, tidak ada ATAU.
Dalam bahasa berbasis C, itu akan menjadi:
Ini hanyalah sebuah aplikasi dari hukum De Morgan :
(A || B) == !(!A && !B)
sumber
if/else
konstruk sama dengan menggunakan OR, hanya dengan nama yang berbeda.if
setara dengan kesetaraan. Biasanya dalam kode mesinif
diimplementasikan sebagai aritmatika diikuti oleh perbandingan ke nol dengan lompatan.and
pendek IFF , sehingga memberikan konsistensi di antara operator.if (a) return true; else if (b) return true;
tampaknya secara moral kurang lebih sama denganif (a OR b) return true;
, tetapi pandangan itu mungkin terbuka untuk diperdebatkan.Jika Anda hanya memiliki
and
dannot
, Anda dapat menggunakan hukum DeMorgan untuk membalikand
:... atau (bahkan lebih sederhana)
...
Dan karena kita semua tampaknya menjadi terpaku pada optimalisasi sesuatu yang hampir selalu tersedia sebagai instruksi mesin, yang bermuara pada:
dll dll dll dll
Karena sebagian besar bahasa menyediakan syarat-dan, kemungkinan besar operator "dan" tetap menyiratkan cabang.
...
Jika yang Anda miliki adalah
nand
(lihat wikipedia ):return nand (nand (arg1, arg1), nand (arg2, arg2))
sumber
return not (not arg1 and not arg2)
nand
solusi murni .Fungsi (ECMAScript)
Yang Anda butuhkan hanyalah definisi fungsi dan panggilan fungsi. Anda tidak memerlukan fungsi percabangan, kondisional, operator atau builtin apa pun. Saya akan mendemonstrasikan implementasi menggunakan ECMAScript.
Pertama, mari kita mendefinisikan dua fungsi yang disebut
true
danfalse
. Kita dapat mendefinisikannya dengan cara apa pun yang kita inginkan, mereka sepenuhnya arbitrer, tetapi kita akan mendefinisikannya dengan cara yang sangat istimewa yang memiliki beberapa kelebihan seperti yang akan kita lihat nanti:tru
adalah fungsi dengan dua parameter yang mengabaikan argumen kedua dan mengembalikan yang pertama.fls
juga merupakan fungsi dengan dua parameter yang mengabaikan argumen pertama dan mengembalikan yang kedua.Mengapa kami menyandikan
tru
danfls
dengan cara ini? Nah, dengan cara ini, kedua fungsi tidak hanya mewakili dua konseptrue
danfalse
, tidak, pada saat yang sama, mereka juga mewakili konsep "pilihan", dengan kata lain, mereka juga merupakanif
/then
/else
ekspresi! Kami mengevaluasiif
kondisi dan meneruskannyathen
blok danelse
blok sebagai argumen. Jika kondisi dievaluasitru
, maka akan mengembalikanthen
blok, jika mengevaluasifls
, akan mengembalikanelse
blok. Ini sebuah contoh:Ini kembali
23
, dan ini:kembali
42
, seperti yang Anda harapkan.Namun, ada kerutan:
Ini mencetak keduanya
then branch
danelse branch
! Mengapa?Yah, itu mengembalikan nilai pengembalian argumen pertama, tetapi mengevaluasi kedua argumen, karena ECMAScript ketat dan selalu mengevaluasi semua argumen ke suatu fungsi sebelum memanggil fungsi. TKI: ia mengevaluasi argumen pertama
console.log("then branch")
, yang hanya mengembalikanundefined
dan memiliki efek samping dari pencetakanthen branch
ke konsol, dan mengevaluasi argumen kedua, yang juga mengembalikanundefined
dan mencetak ke konsol sebagai efek samping. Kemudian, ia mengembalikan yang pertamaundefined
.Di λ-calculus, tempat penyandian ini ditemukan, itu bukan masalah: λ-calculus murni , yang berarti tidak memiliki efek samping; karena itu Anda tidak akan pernah memperhatikan bahwa argumen kedua juga akan dievaluasi. Plus, λ-calculus malas (atau setidaknya, sering dievaluasi dalam urutan normal), artinya, itu tidak benar-benar mengevaluasi argumen yang tidak diperlukan. Jadi, TKI: dalam λ-calculus argumen kedua tidak akan pernah dievaluasi, dan jika ya, kami tidak akan melihat.
Namun, ECMAScript ketat , yaitu selalu mengevaluasi semua argumen. Well, sebenarnya, tidak selalu: yang
if
/then
/else
, misalnya, hanya mengevaluasithen
cabang jika kondisitrue
dan hanya mengevaluasielse
cabang jika kondisifalse
. Dan kami ingin mereplikasi perilaku ini dengan kamiiff
. Untungnya, meskipun ECMAScript tidak malas, ia memiliki cara untuk menunda evaluasi sepotong kode, dengan cara yang sama hampir setiap bahasa lainnya: membungkusnya dalam suatu fungsi, dan jika Anda tidak pernah memanggil fungsi itu, kode tersebut akan tidak pernah dieksekusi.Jadi, kami membungkus kedua blok dalam suatu fungsi, dan pada akhirnya memanggil fungsi yang dikembalikan:
cetakan
then branch
dancetakan
else branch
.Kita bisa menerapkan cara tradisional
if
/then
/else
ini:Sekali lagi, kita memerlukan beberapa pembungkus fungsi tambahan saat memanggil
iff
fungsi dan kurung fungsi panggilan ekstra dalam definisiiff
, untuk alasan yang sama seperti di atas:Sekarang kita memiliki dua definisi tersebut, kita dapat menerapkannya
or
. Pertama, kita melihat tabel kebenaranor
: jika operan pertama adalah benar, maka hasil dari ekspresi sama dengan operan pertama. Kalau tidak, hasil dari ekspresi adalah hasil dari operan kedua. Singkatnya: jika operan pertama adalahtrue
, kami mengembalikan operan pertama, jika tidak, kami mengembalikan operan kedua:Mari kita periksa apakah itu berfungsi:
Besar! Namun, definisi itu terlihat agak jelek. Ingat,
tru
danfls
sudah bertindak seperti bersyarat sendiri, jadi benar-benar tidak perluiff
, dan dengan demikian semua fungsi itu membungkus sama sekali:Itu dia:
or
(ditambah operator boolean lainnya) yang didefinisikan dengan definisi fungsi dan panggilan fungsi hanya dalam beberapa baris:Sayangnya, implementasi ini agak tidak berguna: tidak ada fungsi atau operator dalam ECMAScript yang mengembalikan
tru
ataufls
, mereka semua kembalitrue
ataufalse
, jadi kami tidak dapat menggunakannya dengan fungsi kami. Tapi masih banyak yang bisa kita lakukan. Misalnya, ini adalah implementasi dari daftar yang terhubung sendiri:Objek (Scala)
Anda mungkin telah memperhatikan sesuatu yang aneh:
tru
danfls
memainkan peran ganda, mereka bertindak baik sebagai nilai datatrue
danfalse
, tetapi pada saat yang sama, mereka juga bertindak sebagai ekspresi kondisional. Mereka adalah data dan perilaku , yang digabungkan menjadi satu ... uhm ... "benda" ... atau (berani saya katakan) objek !Memang,
tru
danfls
benda. Dan, jika Anda pernah menggunakan Smalltalk, Self, Newspeak atau bahasa berorientasi objek lainnya, Anda akan memperhatikan bahwa mereka mengimplementasikan boolean dengan cara yang persis sama. Saya akan menunjukkan implementasi seperti ini di sini di Scala:BTW ini adalah alasan Ganti Kondisional Dengan Polimorfisme Refactoring selalu berfungsi: Anda selalu dapat mengganti setiap dan setiap kondisional dalam program Anda dengan pengiriman pesan polimorfik, karena seperti yang baru saja kami tunjukkan, pengiriman pesan polimorfik dapat menggantikan kondisional dengan hanya mengimplementasikannya. Bahasa seperti Smalltalk, Self dan Newspeak adalah bukti keberadaan itu, karena bahasa-bahasa itu bahkan tidak memiliki persyaratan. (Mereka juga tidak memiliki loop, BTW, atau benar - benar segala jenis struktur kontrol bawaan bahasa kecuali untuk pengiriman pesan polimorfik alias panggilan metode virtual.)
Pencocokan Pola (Haskell)
Anda juga bisa mendefinisikan
or
menggunakan pencocokan pola, atau sesuatu seperti definisi fungsi parsial Haskell:Tentu saja, pencocokan pola adalah bentuk eksekusi bersyarat, tetapi sekali lagi, begitu juga pengiriman pesan berorientasi objek.
sumber
False ||| False = False
dan_ ||| _ = True
sebaliknya? :)True ||| undefined
sendiri dalam ghci untuk melihat!Berikut cara lain untuk mendefinisikan OR, atau memang operator logis, menggunakan cara paling tradisional untuk mendefinisikannya: gunakan tabel kebenaran.
Ini tentu saja cukup sepele untuk dilakukan dalam bahasa tingkat yang lebih tinggi seperti Javascript atau Perl tetapi saya menulis contoh ini dalam C untuk menunjukkan bahwa teknik ini tidak tergantung pada fitur bahasa tingkat tinggi:
Anda dapat melakukan hal yang sama dengan AND, NOR, NAND, NOT dan XOR. Kode ini cukup bersih sehingga terlihat seperti sintaksis sehingga Anda dapat melakukan hal-hal seperti ini:
sumber
BinaryOperator or = new TruthTableBasedBinaryOperator(new TruthTable(false, true, true, true));
Cara lain untuk mengekspresikan operator logis sebagai ekspresi aritmatika integer (jika memungkinkan). Cara ini dapat menghindari banyak percabangan untuk ekspresi yang lebih besar dari banyak predikat.
Biarkan Benar menjadi 1 Biarkan Salah menjadi 0
jika penjumlahan keduanya lebih besar dari 1 maka benar atau salah akan dikembalikan.
sumber
booleanExpression ? true : false
sepele sama denganbooleanExpression
.return (arga+argb)>0
return (((arg1 ? 1 : 0)+(arg2 ? 1 : 0)) > 0);
:)arg1 ? 1 : 0;
. Itu adalah ekspresi yang dapat diandalkan untuk mengubah Boolean menjadi angka. Hanya pernyataan pengembalian yang dapat dengan mudah dire-reforasi.Dua bentuk:
ATAU
Memiliki serta keuntungan seperti kode golf menjadi sedikit lebih kecil dari saran lainnya sejauh ini, satu cabang kurang. Bahkan tidak sebodoh mikro-opt untuk mengurangi jumlah cabang jika kita mempertimbangkan penciptaan primitif yang karenanya akan sangat banyak digunakan.
Definisi Javascript
||
mirip dengan ini, yang dikombinasikan dengan pengetikan yang longgar berarti bahwa ekspresifalse || "abc"
memiliki nilai"abc"
dan42 || "abc"
memiliki nilai42
.Meskipun jika Anda sudah memiliki operator logis lain maka suka
nand(not(arg1), not(arg2))
mungkin memiliki keuntungan tanpa percabangan sama sekali.sumber
Selain semua solusi yang diprogram menggunakan if build, dimungkinkan untuk membangun gerbang OR dengan menggabungkan tiga gerbang NAND. Jika Anda ingin melihat bagaimana melakukannya di wikipedia, klik di sini .
Dari sini, ungkapan,
yang menggunakan BUKAN dan DAN memberikan jawaban yang sama dengan ATAU. Perhatikan bahwa penggunaan BUKAN dan DAN hanyalah cara yang tidak jelas untuk mengekspresikan NAND.
sumber
Semua jawaban yang baik telah diberikan. Tetapi saya tidak akan membiarkan itu menghentikan saya.
Kalau tidak:
Saya harap tidak ada yang benar-benar menggunakan pendekatan seperti ini. Mereka ada di sini hanya untuk mempromosikan kesadaran akan alternatif.
Memperbarui:
Karena angka negatif dapat mematahkan kedua pendekatan di atas, berikut ini adalah saran buruk lainnya:
Ini hanya menggunakan Hukum DeMorgan dan menyalahgunakan fakta yang
*
mirip dengan&&
kapantrue
danfalse
diperlakukan seperti1
dan0
masing - masing. (Tunggu, maksudmu ini bukan kode golf?)Inilah jawaban yang layak:
Tapi itu pada dasarnya identik dengan jawaban lain yang sudah diberikan.
sumber
arg1+arg2
, -1 dan 0 untukmax(arg1,arg2)
, dllSalah satu cara untuk mendefinisikan
or
adalah melalui tabel pencarian. Kita dapat membuat ini eksplisit:kami membuat array dengan nilai-nilai yang seharusnya memiliki nilai pengembalian tergantung pada apa
a
. Lalu kami melakukan pencarian. Dalam bahasa seperti C ++,bool
mempromosikan ke nilai yang dapat digunakan sebagai indeks array, dengantrue
being1
danfalse
being0
.Kami kemudian dapat memperluas ini ke operasi logis lainnya:
Sekarang kelemahan dari semua ini adalah itu membutuhkan notasi awalan.
dan sekarang kamu bisa mengetik
true *OR* false
dan berfungsi.Teknik di atas membutuhkan bahasa yang mendukung pencarian bergantung argumen, dan template. Anda mungkin dapat melakukannya dalam bahasa dengan obat generik dan ADL.
Sebagai tambahan, Anda dapat memperpanjang di
*OR*
atas untuk bekerja dengan set. Cukup buat fungsi gratisinvoke
di namespace yang sama denganor_tag
:dan sekarang
set *OR* set
mengembalikan penyatuan keduanya.sumber
Yang ini mengingatkan saya pada fungsi charasteristic:
Ini hanya berlaku untuk bahasa yang dapat memperlakukan boolean sebagai (1, 0). Tidak berlaku untuk Smalltalk atau Python karena boolean adalah kelas. Dalam smalltalk mereka melangkah lebih jauh (ini akan ditulis dalam semacam kodesemu):
Dan ada dua metode untuk dan:
Jadi "logika" ini benar-benar valid dalam pernyataan OP, meskipun itu verbose. Waspadalah, itu tidak buruk. Ini sempurna jika Anda memerlukan fungsi yang bertindak seperti operator matematika berdasarkan, katakanlah, semacam matriks. Orang lain akan menerapkan kubus yang sebenarnya (seperti pernyataan Quine-McCluskey):
Dan Anda akan mengevaluasi atau [a] [b]
Jadi ya, setiap logika di sini valid (kecuali yang diposting menggunakan operator OR bahasa xDDDDDDDD).
Tapi yang paling saya sukai adalah hukum DeMorgan:
!(!a && !b)
sumber
Lihatlah perpustakaan standar Swift dan periksa penerapan pintas ATAU dan pintas DAN operasi, yang tidak mengevaluasi operan kedua jika tidak diperlukan / diizinkan.
sumber
Logikanya sangat benar, tetapi dapat disederhanakan:
Dan mungkin bahasa Anda memiliki operator OR jadi - kecuali itu bertentangan dengan semangat pertanyaan - mengapa tidak
sumber
if arg1 = True or arg2 = True { return true } else { return false }
Lebih baik lagireturn arg1 = True or arg2 = True
,.if condition then true else false
berlebihan.