เหตุใดภาษาจึงไม่มีความสามารถในการเปรียบเทียบค่ากับค่าอื่นมากกว่าหนึ่งค่า [ปิด]


10

พิจารณาสิ่งต่อไปนี้:

if(a == b or c)

ในภาษาส่วนใหญ่จะต้องเขียนเป็น:

if(a == b or a == c)

ซึ่งค่อนข้างยุ่งยากและทำซ้ำข้อมูล

ฉันรู้ว่าไวยากรณ์ตัวอย่างด้านบนของฉันค่อนข้าง clunky เล็กน้อย แต่ฉันแน่ใจว่ามีวิธีที่ดีกว่าในการถ่ายทอดความคิด

ทำไมไม่มีภาษาให้มากกว่านี้ มีปัญหาเรื่องประสิทธิภาพหรือไวยากรณ์หรือไม่


6
SQL เสนอสิ่งนั้น: โดยที่ A IN (B, C)
วันพฤหัสบดีที่

4
ฉันไม่ได้ขอภาษาที่ให้มาหรือมีได้ แต่ทำไมไม่มีภาษาให้มากกว่านี้ มีปัญหาเรื่องประสิทธิภาพหรือไวยากรณ์หรือไม่
Zeroth

8
ในการพูดคุยทั่วไปของ @thursdaysgeek คำตอบในภาษาส่วนใหญ่คุณมักจะทำเช่นนั้นด้วยชุดบรรจุ (หรือรายการหรือทูเปิลหากทำได้ง่ายกว่า) มันทำงานได้เหมือนกันและหลีกเลี่ยงปัญหาไวยากรณ์ที่อาจเกิดขึ้นได้ จากตัวอย่างของคุณ "b หรือ c" หมายถึงชุด "{b, c}" หรือเป็นตัวดำเนินการเช่น || ? ในหลาม "B หรือ C" หมายถึง "ค่าของขถ้าเป็นจริงหรืออื่น ๆ ที่คุ้มค่าของ c"
ร็อบ

4
โดยพื้นฐานแล้วนี่เป็นปัญหาด้านไวยากรณ์ ปัญหาในมือคือการมีวิธีที่เข้าใจง่ายในการลดความแตกต่างระหว่าง "b หรือ c" และ "b or'd with c"
YoungJohn

2
มันค่อนข้างแฮ็คกับกรณีพิเศษa == b or cและมันก็ไม่ได้ยอดเยี่ยมเท่าไหร่ IMHO

คำตอบ:


24

ปัญหาเกี่ยวกับไวยากรณ์คือ - ต้องใช้ไวยากรณ์

ไม่ว่าไวยากรณ์ของคุณจะเป็นอะไรคนที่ใช้ภาษาก็ต้องเรียนรู้ มิฉะนั้นพวกเขาจะเสี่ยงต่อการดูรหัสและไม่รู้ว่ามันทำอะไร ดังนั้นโดยทั่วไปถือว่าเป็นสิ่งที่ดีหากภาษามีรูปแบบง่าย ๆ ที่จัดการกรณีต่างๆได้อย่างหมดจด

ในตัวอย่างเฉพาะของคุณคุณกำลังพยายามใช้ตัวดำเนินการมัด (ฟังก์ชันที่รับอาร์กิวเมนต์สองตัว แต่ถูกเขียนArgument1 Operator Argument2) และพยายามขยายไปยังอาร์กิวเมนต์หลายตัว นั่นไม่ได้ผลมากนักเพราะจุดทั้งหมดของโอเปอเรเตอร์ infix เท่าที่มีอยู่คือให้โอเปอเรเตอร์อยู่ระหว่างอาร์กิวเมนต์ 2 ตัว การขยายไป(Argument1 Operator Argument2 MagicallyClearSymbol Argument3...)ยังดูเหมือนจะไม่เพิ่มความชัดเจนEquals(Arg1,Arg2,...)มากนัก โดยทั่วไปแล้วจะใช้เพื่อเลียนแบบการคำนวณทางคณิตศาสตร์ที่มัดคนคุ้นเคยกับซึ่งจะไม่เป็นความจริงของทางเลือกซินแท็คซ์

จะไม่มีปัญหาด้านประสิทธิภาพเฉพาะที่เกี่ยวข้องกับความคิดของคุณนอกจากตัวแยกวิเคราะห์จะต้องจัดการกับไวยากรณ์กับกฎการผลิตอื่นหรือสองซึ่งอาจมีผลต่อความเร็วในการแยกวิเคราะห์เล็กน้อย สิ่งนี้อาจสร้างความแตกต่างสำหรับภาษาที่แปลหรือรวบรวม JIT แต่อาจไม่แตกต่างกันมาก

ปัญหาใหญ่ที่มีความคิดที่เป็นเพียงที่ทำให้จำนวนมากกรณีพิเศษในภาษาที่มีแนวโน้มที่จะเป็นความคิดที่ดี


1
นอกเหนือ: Scala .มีผู้ประกอบการมัดกับจำนวนข้อของการขัดแย้งเป็นผู้ประกอบการมัดเป็นวิธีการเพียงสายได้โดยไม่ต้อง arg1 op (arg2, arg3)ดังนั้นพวกเขาต้องการจะเขียนเป็น ไม่สวยงามอย่างแน่นอน แต่จำเป็นในบางสถานที่ในบริบทของภาษานั้น
amon

สิ่งที่เกี่ยวกับif my_var in (a, b)แล้ว? นี่ไม่ใช่คำถามของการใช้เครื่องมือที่เหมาะสมสำหรับงานนี้อีกหรือ

จุดที่ดี ไวยากรณ์ภาษาควรเป็นสิ่งสำคัญของภาษาและจากนั้นคุณสร้างไลบรารีที่ด้านบนของมัน หากภาษานั้นยุ่งเหยิงไปกับน้ำตาลที่มีประโยชน์ "ประโยชน์" มันจะใช้ยากขึ้น ทุกคนไม่ต้องการขณะที่คนอื่นต้องการa == b or c a == b or c but not dIMO นั่นคือจุดที่ฟังก์ชั่นยูทิลิตี้ / ไลบรารีมาช่วยเหลือ
อัลลัน

บางทีสิ่งที่จำเป็นคือวิธีการที่วิธีการหนึ่งสามารถระบุได้ว่าการเรียกที่มีจำนวนข้อโต้แย้งโดยพลการควรได้รับการจัดการเป็นการโทรหลายครั้งโดยมีผลลัพธ์รวมกันในบางวิธี ถ้าf().Equals(a,b,c); สามารถประเมินได้(var temp=f(); temp.Equals(a)||temp.Equals(b)||temp.Equals(c))ว่าไวยากรณ์นั้นจะสมบูรณ์แบบ แต่ถ้าประเมินint[] arr = {a,b,c}; f().Equals(arr);ว่าไม่ดีนักโดยเฉพาะถ้าอาร์เรย์ใหม่ต้องถูกสร้างขึ้นสำหรับการโทรแต่ละครั้ง
supercat

6

เพราะมันไม่ใช่ปัญหาและการแก้ไขมันจะนำมาซึ่งผลประโยชน์เป็นศูนย์โดยทั่วไป แต่การนำไปใช้นั้นจะทำให้เกิดต้นทุนที่ไม่เป็นศูนย์

ฟังก์ชั่นพื้นฐานที่มีอยู่และเช่นนั้นจริงทุกภาษามีให้สามารถทำงานได้อย่างสมบูรณ์แบบในสถานการณ์นี้ถ้ามันปรับขนาดเป็นขนาดที่a == b || a == cจะไม่ตัดมัน


2
+1 แต่ฉันคิดว่าคำตอบจะได้รับการปรับปรุงโดยการแสดงหนึ่งหรือสองของ "ฟังก์ชันตามช่วงที่มีอยู่ซึ่งจริงทุกภาษา [ข้อเสนอ]" ดังนั้นทางเลือกนี้จะชัดเจนขึ้น
Avner Shahar-Kashtan

คุณสามารถพิสูจน์ได้หรือไม่ว่า "นำมาซึ่งผลประโยชน์เป็นศูนย์โดยพื้นฐาน แต่การนำไปใช้นั้นจะทำให้เกิดต้นทุนที่ไม่เป็นศูนย์"?
Darek Nędza

3
@ DarekNędzaครึ่งหลังไม่ควรจะเป็นที่ถกเถียง: ทุกคุณลักษณะต้องมีการคิดผ่านการดำเนินการทดสอบการบันทึกไว้และได้รับการสนับสนุน ไม่มีขั้นตอนเหล่านี้ฟรีภายใต้ตัวชี้วัดที่สมเหตุสมผล (เวลาของประชาชนต้นทุนของโอกาสความซับซ้อนค่าใช้จ่ายทางการเงินหากมีใครจ่ายเงินให้ทำงานและอื่น ๆ )

@ AvnerShahar-Kashtan เห็นด้วย - สำหรับฉันมันไม่ชัดเจนว่ามันจะดูพูดจาวาหรือ sh หรือ zsh? ตกลงเขาอาจมีภาษา 'ทันสมัย' โดยนัย Groovy?
Volker Siegel

ใน PHP in_array($a, [$b, $c, $d, $e, $f])ก็ต้องการมีลักษณะเหมือน : P
cHao

6

บางภาษามีคุณสมบัติดังกล่าว เช่นใน Perl6 เราสามารถใช้Junctionsซึ่งเป็น“ superpositions” ของสองค่า:

if $a == any($b, $c) {
    say "yes";
}

# syntactic sugar for the above
if $a == $b | $c {
    say "yes";
}

ทางแยกช่วยให้เราสามารถแสดงการดำเนินงานในชุดของข้อมูลค่อนข้างรัดกุมคล้ายกับวิธีการดำเนินงานสเกลาร์กระจายไปทั่วคอลเลกชันในบางภาษา เช่นการใช้ Python กับ numpy การเปรียบเทียบสามารถแจกจ่ายได้มากกว่าค่าทั้งหมด:

import numpy as np
2 == np.array([1, 2, 3])
#=> np.array([False, True, False], dtype=np.bool)
(2 == np.array([1, 2, 3])).any()
#=> True

อย่างไรก็ตามวิธีนี้ใช้ได้กับประเภทดั้งเดิมเท่านั้น

ทำไมการรวมทางแยกจึงมีปัญหา? เนื่องจากการดำเนินการบน junction แจกจ่ายผ่านค่าที่มีอยู่วัตถุ junction จึงทำตัวเหมือนพร็อกซีสำหรับการเรียกใช้เมธอด - ระบบบางอย่างที่นอกเหนือจากการพิมพ์เป็ดสามารถจัดการได้

ปัญหาระบบประเภทสามารถหลีกเลี่ยงได้หากได้รับอนุญาตให้ใช้จุดเชื่อมต่อดังกล่าวเป็นไวยากรณ์พิเศษรอบตัวดำเนินการเปรียบเทียบ แต่ในกรณีนี้พวกเขาถูก จำกัด มากจนพวกเขาไม่ได้เพิ่มมูลค่าเพียงพอที่จะเพิ่มในภาษาใด ๆ ที่มีสติ พฤติกรรมเดียวกันสามารถแสดงโดยใช้การตั้งค่าหรือการสะกดการเปรียบเทียบทั้งหมดด้วยตนเองและภาษาส่วนใหญ่ไม่เชื่อในการเพิ่มไวยากรณ์ซ้ำซ้อนหากมีวิธีการแก้ปัญหาที่สมบูรณ์แบบแล้ว


ว่าตัวอย่าง numpy 2 in [1, 2, 3]โดยเฉพาะอย่างยิ่งอาจจะเขียนใหม่เป็นที่ชัดเจน ในทางกลับกันถ้า numpy มี a .all()หรืออย่างใดอย่างหนึ่ง python ธรรมดาที่เทียบเท่าจะไม่กระชับ
Izkata

@Izkata ฉันไม่ได้ใช้การตั้งค่าเป็นพิเศษ ในขณะที่ตัวอย่างของฉันใช้==โอเปอเรเตอร์เรายังสามารถใช้<แทน - คุณinอยู่ที่ไหนตอนนี้ การแยกนั้นมีความกว้างมากกว่าการทดสอบการเป็นสมาชิกเนื่องจากการดำเนินการบนทางแยกกระจายไปทั่วสมาชิกทั้งหมด - (x|y).fooคือx.foo|y.fooจนกว่าทางแยกจะยุบลงในค่าเดียว รหัส NumPy ที่ให้ไว้แสดงการแปลที่เท่าเทียมกัน แต่ verbose มากขึ้นของทางแยก Perl6 สมมติว่าประเภทดั้งเดิม
amon

2

ในภาษาที่มีมาโครคุณสามารถเพิ่มสิ่งนี้ได้อย่างง่ายดายหากยังไม่มี พิจารณาไม้

(define-syntax-rule (equal-any? a b ...)
  (or (equal? a b) ...))
(equal-any? "a" "b" "a")
> #t

ในภาษาอื่น ๆ โดยไม่ต้องใช้โปรแกรมเมตาแกรมคุณอาจจะจัดรูปแบบใหม่ในการตั้งค่า / ตรวจสอบความเป็นสมาชิกของรายการ:

if a ∈ {b, c}

2
สองรายการแรกตรวจสอบว่าอาร์กิวเมนต์ทั้งหมดเท่ากันหรือไม่ OP ต้องการตรวจสอบว่าอาร์กิวเมนต์แรกเท่ากับรายการใด ๆ ต่อไปนี้หรือไม่ ตัวอย่างที่สามที่คุณแสดงน่านับถืออย่างเคารพ

@delnan ขอโทษฉันเข้าใจผิดสิ่ง ฉันแก้ไขมันแล้ว
ฟิล

2

ใน==โอเปอเรเตอร์ภาษาบางภาษา ตัวอย่างเช่นใน JavaScript 0มีค่าเท่ากับ''และ'0'จากนั้น''และ'0'จะไม่เท่ากับ eachother คุณสมบัติเพิ่มเติมดังกล่าวใน PHP

ก็หมายความว่าa == b == cจะเพิ่มความคลุมเครืออีกเพราะมันได้ผลผลที่แตกต่างกันขึ้นอยู่กับว่าจะตีความว่าเป็นหรือ(a == b) & (a == c)(a == b) & (a == c) & (b == c)


2

ในภาษาส่วนใหญ่ควรทำได้โดยการเขียนInฟังก์ชั่นเล็กน้อยทำไมจึงทำให้มันเป็นส่วนหนึ่งของภาษาจริง

Linq Contains()ตัวอย่างเช่นมี

เอาล่ะสำหรับคนเดินถนนทุกคนนี่คือการดำเนินการของฉันใน C #:

public static bool In<T>(this T obj, params T[] values)
{
    for(int i=0; i < values.Length; i++)
    {
        if (object.Equals(obj, values[i]))
            return true;
    }
    return false;
}

ที่ทำงานในช่วงของค่ารันไทม์ไม่ใช่ tuple เนื่องจากรหัสของ OP สามารถแสดงเป็น
DeadMG

ดูเหมือนว่าเพียงเพราะง่ายไม่ได้หมายความว่าไม่ควรทำ มัน ... พิจารณาการก่อสร้าง เหตุใดเราจึงต้องเขียนฟังก์ชันการทำงานและอัลกอริธึมพื้นฐานทั้งหมดเหล่านี้ด้วยตนเองซ้ำแล้วซ้ำเล่า?
Zeroth

5
@Zeroth บางทีคุณอาจจะเขียนสิ่งเดียวกันซ้ำแล้วซ้ำอีก แต่คนอื่น ๆ มักจะใช้กลไกที่เป็นนามธรรมโดยภาษาของพวกเขาแทน ถ้าคุณเห็นว่าตัวเองเขียนa == b || a == cหลายครั้งบางทีมันอาจจะถึงเวลาที่equals_any(a, {b, c})
อมร

A "ประกอบด้วย" การดำเนินการไม่ได้อย่างง่ายดายขยายไปถึงสิ่งปกเหมือนและif (a > (b or c)) if (a mod (b or c) == 2)
tobyink

1
มีใครบางคนพูดว่า pedants? :) มันเป็นลูป foreach ดังนั้นจึงไม่มีiตัวแปร และโดยรวมแล้วดูเหมือนว่าจะถูกเขียนขึ้นหลังจากที่คุณมีวันที่ยาวนาน :) เนื่องจากการใส่ทั้งสองreturn trueและreturn falseภายในลูปที่นี่หมายความว่าไม่มีทางที่มันจะทำให้เหนือกว่าการทำซ้ำครั้งแรก คุณจะเปรียบเทียบกับคนแรกvalueเท่านั้น โดยวิธีการทำไมไม่ใช้Anyเป็น @Bob แนะนำและทำให้มันง่ายขึ้นreturn values.Any(value => Object.Equals(obj, value));
Konrad Morawski

1

"if (a == b หรือ c)" ทำงานได้ในภาษาส่วนใหญ่: ถ้า a == b หรือถ้า c ไม่ได้เป็นค่าลบ null หรือศูนย์

บ่นว่ามันละเอียดมากพลาดจุด: คุณไม่ควรซ้อนสิ่งต่าง ๆ ลงในเงื่อนไข หากคุณต้องการเปรียบเทียบหนึ่งค่ากับจำนวนอื่น ๆ โดยพลการให้สร้างรูทีนย่อย


3
ภาษาใดที่ใช้สร้าง "มากที่สุด"
FrustratedWithFormsDesigner

1
@FrustratedWithFormsDesigner ดีถ้าcประเมินบูลแล้วสวยมากภาษาใด ๆ สามารถจัดการa == b || c:)
ไบรอัน S

@BrianS: ผมถือว่า OP if(a == b or c)หมายถึงไวยากรณ์ที่แท้จริง ฉันต้องหยุดพักฉันคิดว่า ... : P
FrustratedWithFormsDesigner

@FrustratedWithFormsDesigner Lisp! ... huh? ... :)
Volker Siegel

3
นี่เป็นจุดที่พลาดไม่ได้จริงๆ if (a == b or c)เป็นนามแฝงรหัสเพื่อตรวจสอบว่าaมีค่าเท่ากับbหรือเท่ากับa cไม่ใช่การตรวจสอบว่าcไม่ใช่ศูนย์
hvd

1

โดยปกติแล้วคุณต้องการให้ไวยากรณ์น้อยที่สุดและอนุญาตให้กำหนดโครงสร้างดังกล่าวในภาษาของตัวเอง

ตัวอย่างเช่นใน Haskell คุณสามารถแปลงฟังก์ชันใด ๆ ที่มีสองอาร์กิวเมนต์ขึ้นไปเป็นตัวดำเนินการมัดโดยใช้ backticks อนุญาตให้คุณเขียน:

if a `elem` [b, c] then ... else ...

โดยelemเป็นเพียงฟังก์ชั่นปกติที่รับอาร์กิวเมนต์สองตัวคือค่าและรายการค่าและตรวจสอบว่าส่วนแรกเป็นองค์ประกอบของส่วนที่สองหรือไม่

ถ้าคุณต้องการที่จะใช้andแทนor? ใน Haskell คุณสามารถใช้สิ่งต่อไปนี้แทนการรอให้ผู้ขายคอมไพเลอร์ใช้คุณลักษณะใหม่:

 if all (== a) [b, c] then ... else ...

1
ทำไมคนเราต้องการทำให้ไวยากรณ์มีค่าน้อยที่สุด? อะไรคือการแลกเปลี่ยนที่เกิดขึ้นที่นั่น? อย่าประกาศเช่นนี้หากไม่มีอาร์กิวเมนต์สนับสนุน ;)
Zeroth

1

บางภาษาเสนอสิ่งนี้ - ในระดับหนึ่ง

อาจจะไม่เป็นตัวอย่างเฉพาะของคุณแต่ใช้ตัวอย่างเช่นสายหลาม

def minmax(min, max):
    def answer(value):
        return max > value > min
    return answer

inbounds = minmax(5, 15)
inbounds(7) ##returns True
inbounds(3) ##returns False
inbounds(18) ##returns False

ดังนั้นบางภาษาก็ใช้ได้ดีกับการเปรียบเทียบหลายอย่างตราบใดที่คุณแสดงมันอย่างถูกต้อง

น่าเสียดายที่มันไม่ได้ผลเหมือนที่คุณคาดหวังไว้สำหรับการเปรียบเทียบ

>>> def foo(a, b):
...     def answer(value):
...         return value == a or b
...     return answer
... 
>>> tester = foo(2, 4)
>>> tester(3)
4
>>> tester(2)
True
>>> tester(4)
4
>>> 

"คุณหมายความว่ายังไงมันจะคืนค่า True หรือ 4?" - การจ้างงานหลังจากคุณ

ทางออกหนึ่งในกรณีนี้อย่างน้อยก็กับ Python ก็คือใช้มันต่างกันเล็กน้อย:

>>> def bar(a, b):
...     def ans(val):
...             return val == a or val == b
...     return ans
... 
>>> this = bar(4, 10)
>>> this(5)
False
>>> this(4)
True
>>> this(10)
True
>>> this(9)
False
>>> 

แก้ไข: ต่อไปนี้จะทำสิ่งที่คล้ายกันอีกครั้งใน Python ...

>>> def bar(a, b):
...     def answer(val):
...             return val in (a, b)
...     return answer
... 
>>> this = bar(3, 5)
>>> this(3)
True
>>> this(4)
False
>>> this(5)
True
>>> 

ดังนั้นไม่ว่าคุณจะใช้ภาษาใดมันอาจไม่ใช่ว่าคุณไม่สามารถทำได้เพียงแค่คุณต้องดูให้ละเอียดก่อนว่าตรรกะทำงานอย่างไร โดยทั่วไปแล้วเป็นเรื่องของการรู้ว่าคุณ 'ขอจริง' ภาษาที่จะบอกคุณ


1

เมธอด indexOf ที่ใช้กับ Array นั้นมีหลายภาษาที่มีให้เปรียบเทียบค่ากับหลาย ๆ คนดังนั้นฉันเดาว่าโอเปอเรเตอร์พิเศษไม่สมเหตุสมผล

ในจาวาสคริปต์ที่จะเขียน:

if ( [b, c].indexOf(a) != -1 ) { ....  }

0

คุณถามว่าทำไมเราไม่ทำเช่นนี้: if(a == b or c)

Python ทำสิ่งนี้อย่างมีประสิทธิภาพจริง ๆ แล้วมีประสิทธิภาพมากที่สุดด้วยset:

if a in set([b, c]):
    then_do_this()

สำหรับการทดสอบการเป็นสมาชิก 'set' จะตรวจสอบว่าองค์ประกอบของแฮชเหมือนกันและเปรียบเทียบความเท่าเทียมกันเท่านั้นดังนั้นองค์ประกอบ b และ c จะต้อง hashable มิฉะนั้นรายการจะเปรียบเทียบความเท่าเทียมกันโดยตรง:

if a in [b, c]:
    then_do_this()

0

ภาษาสไตล์ APL ช่วยให้คุณสามารถเปรียบเทียบสเกลาร์กับแต่ละองค์ประกอบในเวกเตอร์ในการดำเนินการครั้งเดียว สิ่งนี้สร้างเวกเตอร์บูลีน ตัวอย่างเช่นฉันต้องการโปรโมตเครื่องคิดเลข apl ที่มีคุณลักษณะน้อยที่สุดของฉันinca ( ล่ามออนไลน์ )

   a<5
5 
   b<4
4 
   c<5
5 
   a=b c
0 1 

เพื่อลดค่านี้ให้เป็นค่าเดียวเราสามารถทำแบบรวมหรือโดยการรวมและการตรวจสอบที่ไม่ใช่ศูนย์

   0!+/a=b c
1 
   c<6
6 
   0!+/a=b c
0

ดังนั้นอย่างที่คำตอบอื่น ๆ บอกว่าปัญหาคือไวยากรณ์ ในระดับหนึ่งพบว่ามีการค้นพบวิธีแก้ปัญหาทางไวยากรณ์ด้วยค่าใช้จ่ายจำนวนมากในการเรียนรู้กระบวนทัศน์ของอาเรย์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.