为什么没有更多的语言能够将一个值与另一个值进行比较?[关闭]


10

考虑以下:

if(a == b or c)

在大多数语言中,这需要写成:

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

这有点麻烦并且会重复信息。

我知道我上面的示例语法有点笨拙,但是我确信有更好的方法来传达这个想法。

为什么没有更多的语言提供它?是否存在性能或语法问题?


6
SQL提供以下内容:A IN(B,C)
2014年

4
我不是在要求提供或可以提供它的语言,但是为什么没有更多的语言可以提供它呢?是否存在性能或语法问题?
2014年

8
为了概括@thursdaysgeek的答案,在大多数语言中,通常使用集合包含来实现。(如果更容易,也可以使用列表或元组。)它的工作原理相同,避免了一些潜在的棘手语法问题。在您的示例中,“ b或c”是指集合“ {b,c}”还是is或||等运算符。?在python中,“ b或c”表示“ b的值为true,否则为c的值”
Rob

4
本质上,这是一个语法问题。当前的问题是采用一种直观的方法来消除“ b或c”与“ b或与c一起使用”之间的区别。
YoungJohn

2
在特殊情况下a == b or c,这很不客气,恕我直言,甚至还不够好。

Answers:


24

语法问题是–它需要语法。

无论您的语言使用哪种语法,使用该语言的人们都必须学习它。否则,他们冒着看到代码而又不知道代码做什么的风险。因此,如果一种语言具有可以轻松处理很多情况的简单语法,通常被认为是一件好事。

在您的特定示例中,您尝试采用infix运算符(一个带有两个参数但被编写的函数Argument1 Operator Argument2),并试图将其扩展为多个参数。这并不是很干净,因为在某种程度上,中缀运算符的全部要点是将运算符放在2个参数之间。扩展到(Argument1 Operator Argument2 MagicallyClearSymbol Argument3...)似乎并没有增加太多的清晰度Equals(Arg1,Arg2,...)。Infix通常还用于模拟人们熟悉的数学约定,而对于其他语法则不是这样。

除了您的想法没有任何特定的性能问题外,解析器将不得不处理具有另一条或两条生产规则的语法,这可能会对解析速度产生轻微影响。对于解释型或JIT编译语言,这可能会有所不同,但可能不会有很大的不同。

这个想法的更大问题是,用一种语言编写很多特殊情况往往是个坏主意


1
另外:Scala具有带任意数量参数的infix运算符,因为infix运算符只是不带的方法调用.。因此它们将被写为arg1 op (arg2, arg3)。并非完全漂亮,但在某些地方需要使用该语言。
阿蒙2014年

那怎么if my_var in (a, b)办 这不就是为工作使用正确工具的问题吗?

好点。语言语法应该是该语言的基本要素,然后您可以在其之上构建库。如果该语言过于用“有用的”语法糖弄得一团糟,那么它将变得更难使用。不是每个人都需要,a == b or c而其他人则需要a == b or c but not d。IMO是拯救实用程序功能/库的地方。
艾伦2014年

也许需要的是一种方法,通过该方法,方法可以指定具有任意数量的参数的调用应作为多个调用处理,并以某种方式组合结果。如果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'5

您能证明它“带来的收益基本上为零,但实施带来的收益却为非零”吗?
DarekNędza2014年

3
@DarekNędza下半年不应该是有争议的:每一个功能必须通过被认为,实施,测试,文档,并支持。在任何合理的度量标准下(人的时间,机会成本,复杂性,金钱成本,如果有人付钱进行工作等等),这些步骤都不是免费的。

@ AvnerShahar-Kashtan同意-对我来说,它在Java,sh或zsh中的外观不是很明显?好的,他可能暗示了“现代”语言。时髦?
Volker Siegel

在PHP中,它看起来像in_array($a, [$b, $c, $d, $e, $f])。:P
cHao 2014年

6

某些语言确实具有此类功能。例如,在Perl6中,我们可以使用Junctions,它们是两个值的“叠加”:

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

但是,这仅适用于选定的原始类型。

为什么路口有问题?因为联结上的操作分布在包含的值上,所以联结对象本身的行为就像方法调用的代理一样,除了鸭子类型之外,很少有类型系统可以处理。

如果只允许这样的连接作为比较运算符周围的特殊语法,则可以避免类型系统问题。但是在这种情况下,它们的局限性太大,以至于它们无法添加足够的价值以添加到任何理智的语言中。可以使用set操作或手动拼出所有比较来表达相同的行为,并且如果已经有一个非常好的解决方案,则大多数语言都不相信添加冗余语法。


该特定的numpy示例可以更清晰地重写为2 in [1, 2, 3]。另一方面,如果numpy具有a .all()或诸如此类的含义,则等效的纯Python几乎不那么简洁。
2014年

@Izkata我专门不使用设置操作。虽然我的示例确实使用了==运算符,但我们也可以使用<-您in现在在哪里?结点比集合成员资格测试更笼统,因为结点上的操作分布在所有成员上- (x|y).foox.foo|y.foo,直到结点最终折叠为单个值为止。假定原始类型,所提供的NumPy代码显示Perl6结的完全等效但更详细的翻译。
阿蒙2014年

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对不起,我误会了东西。我已经编辑了
菲尔(Phil)2014年

2

在某些(流行)语言中,==运算符不是可传递的。例如在JavaScript 0等于既'''0',但后来'''0'彼此不相等。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;
}

它在值的运行时范围内运行,而不是元组,因为OP的代码可以表示为元组。
DeadMG

看起来,仅仅是因为它简单,并不意味着不应该这样做。它...考虑建设。为什么我们总是不得不一遍又一遍又一遍地手动编写所有这些基本功能和算法?
2014年

5
@Zeroth也许您在一遍又一遍地写同一件事,但是其他人倾向于使用其语言提供的抽象机制。如果您看到自己a == b || a == c多次写作,也许是时候了equals_any(a, {b, c})
2014年

“包含”实现不容易扩展到覆盖诸如if (a > (b or c))和的东西if (a mod (b or c) == 2)
tobyink 2014年

1
有人说过学徒吗?:)这是一个foreach循环,因此没有i变量。总的来说,这似乎是在您度过了漫长的一天之后写的:)因为将两者return truereturn false循环都放在此处意味着没有办法使它超出第一次迭代。您只是在与第一个进行比较value。顺便说一句,为什么不Any按照@Bob的建议使用,并将其简化为return values.Any(value => Object.Equals(obj, value));
Konrad Morawski,2014年

1

“ if(a == b或c)”适用于大多数语言:如果a == b或c不为负,为null或为零。

抱怨它太冗长就错了这一点:您不应该将许多东西堆成条件对象。如果需要将一个值与任意数量的其他值进行比较,则构建一个子例程。


3
哪些语言构成“最多”?
FrustratedWithFormsDesigner 2014年

1
@FrustratedWithFormsDesigner,好吧,如果c计算结果为布尔值,那么几乎所有语言都可以处理a == b || c:)
Brian S

@BrianS:我认为OP的意思是字面语法if(a == b or c)。我想休息一下...:P
FrustratedWithFormsDesigner 2014年

@FrustratedWithFormsDesigner Lisp!...是吗?:)
Volker Siegel

3
这确实错过了问题的重点。if (a == b or c)是检查是否a等于ba等于的伪代码c。这并不意味着要检查它c是否为非零。
2014年

1

通常,您希望最小化语法,而是允许在语言本身中定义此类构造。

例如,在Haskell中,您可以使用反引号将具有两个或多个参数的任何函数转换为infix运算符。这使您可以编写:

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

这里elem只是一个带有两个参数的普通函数-一个值和一个值列表-并检查第一个是否为第二个元素。

如果要使用and代替该or怎么办?在Haskell中,您可以仅使用以下内容,而不必等待编译器供应商实现新功能:

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

1
为什么要尽量减少语法?到底权衡是什么?不要在没有支持的情况下进行此类声明。;)
2014年

1

某些语言确实在某种程度上提供了这一点。

也许不作为您的特定示例,但以Python行为例:

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方法可以将一个值与其他几种语言进行比较,所以我猜想一个特殊的运算符没有多大意义。

在javascript中会这样写:

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

0

您问我们为什么不能这样做: if(a == b or c)

实际上,Python使用以下命令非常有效地做到了这一点set

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

对于成员资格测试,“设置”检查元素的哈希值是否相同,然后才进行相等性比较,因此元素b和c必须是可哈希的,否则列表将直接进行相等性比较:

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

因此,正如其他答案所说,问题是语法。从某种程度上来说,语法的解决方案已经被发现,在学习阵列模式的也许是沉重的代价。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.