Boolean b1 = scopes.stream()
.anyMatch(x -> x.getProcessStatus() != complete || x.getProcessStatus() != close);
我写了这么一段代码,编译器告诉我这是有问题的,大家可以先想一下编译器提示了什么,下面有答案和我的疑问。
这个表达式是恒为 true 的,我是编译器告诉我后,想了一会才确认这个问题,我觉得奇怪的是这种判断应该是一种逻辑直觉,我没有这种直觉,我好奇这种直觉的缺失是怎么造成的?
1
AoEiuV020JP 359 天前
啊这,我第一眼也没发现,似乎脑补成了&&,
|
2
cleanery 359 天前 1
x.getProcessStatus() != complete || x.getProcessStatus() != close
两个不等, 或 只有一种情况才是 false 就是 x.getProcessStatus() == complete && x.getProcessStatus() == close 被满足的时候 |
3
cleanery 359 天前
你缺失的应该是等效替代的直觉, 看到这种表达式,我一般是去掉否定的同时逆转 或/与
判断条件尽量不要用否定, 因为人是没有否定直觉的。 如果用否定,也尽量让条件简单清晰 举个例子, 不要想小白兔--- 不要想小白兔--- 不要想小白兔--- 不要想小白兔 |
4
laqow 359 天前
交集是与,并集是或,但语言上与也可以是并集的意思
|
5
geelaw 359 天前
这段代码不能推断任何事情——都不知道 scopes 、x 、complete 、close 是什么!假设 scopes.stream() 是 sensible 的。
如果 scopes 是空集,则 anyMatch 当然永远是 false 。 如果 scopes 不是空集,那么 getProcessStatus() 可能有副作用,连续调用两次不一定返回相同的数值。 我们也不知道 complete 和 close 是不是相等。 如果假设 getProcessStatus() 无副作用,且 complete 和 close 不相等,那么 b1 的结果等于 scopes 是否是空,这依然是非平凡的,除非上文里编译器可以推断 scopes 非空。 培养逻辑直觉的第一步是放弃错误的直觉(也就是所谓的“想当然”)。 |
6
NoOneNoBody 359 天前
人类习惯“二选一”,好多多选题都习惯(潜意识)简化为“二选一”处理,这样可以结果单一化,从而达到问题简单化,便于思考。大部分时候确实效果不错,因为大部分情况下,多选的选择肢并非各向平均,往往大概率是走向两种最受关注的结果,其他就忽略了
例如很常见的例子,“排除他杀”,过半数人马上想到自杀 所以“全集”切割为多项,靠直觉往往难以完整覆盖,就是把分出来的各项不能重新拼合为原来的全集 |
7
yxd19 359 天前
@geelaw
1. 如果有人写了一个叫 getProcessStatus 的带副作用的函数,你可以打他。 2. 如果有人写了两个相等的叫 complete 和 close 的常量,你可以打他。 3. 如果有人用 xs.anyMatch(x -> true)判断 xs 是否为空,你可以打他。 |
8
mohulai 359 天前
啥玩意 别人又不知道你 ProcessStatus 只有 complete close 两个状态
|
9
geelaw 359 天前
@yxd19 #7 我不确定你为什么会认为名字类似 getProcessStatus 的方法是无副作用的,举个非常自然的例子,如果 x 对象基于操作系统级别的进程,那么 getProcessStatus 很可能每次调用的时候都会检查操作系统级别的进程是否结束,并根据操作系统级别的进程的结束状态(还在运行、以 0 退出、以 1 退出、以其他返回值退出)决定返回值。调用操作系统级别检查进程状态的 API 相当于某种同步 (synchronization) 操作,永远属于有副作用操作。
从您打人的条件来看,似乎光是把 complete/close 写成小写就可以发动您打人的动作了?实际上,同一个数值具有多个不同的同类型枚举名字的状况不少见。我想没有什么人在“正经”的程序里用 xs.anyMatch(x -> true) 判空,但不代表它的行为不是如此。 另外您似乎忘了:当下的主题是形式逻辑,不是编程最佳实践。 |
10
yxd19 359 天前
@geelaw 是在聊形式逻辑,可是不添加足够多的前提假设怎么聊形式逻辑呀。比如要讨论“去买一斤橘子,如果有西瓜就买一个”这句话的逻辑,当然要首先靠常识(“编程最佳实践”)把这个不严密的说法改写成(相对)严密的说法(去买一斤橘子;如果有西瓜就买一个西瓜),来显露出形式逻辑,然后把重点放到逻辑上,而不是宣称这句话可能有两种不同的理解方式啊。
我想你也知道 lz 只不过是突然发现「天不是甲或天不是乙」恒为真这件事,你当然可以认为这件事是初等的、没啥可讨论的,但是也没必要把讨论拉到 lz 在这个帖子中并不关注的另一部分。这对于其他人理解 lz 的重点没啥好处。 |
11
geelaw 359 天前 via iPhone
@yxd19 #10 我并不是这么理解的,楼主的话的意思显然是编译器认为 b1 是恒为 true ,这才是让我惊讶的点——因为我以为编译器不会追踪集合是否是空。
此外就是这段代码看起来像 Java ,而我以为 Java 编译器不会做这么多的检查,尤其是 x 的静态类型上的 getProcessStatus 非常可能不是密封(最终)方法,从而不能假设是无副作用,对它静态分析非常困难。 但总之,我的第一条回复的另一层含义是楼主说话应该把上下文说清楚。 另外怎么突然用清朝微积分语言(? |
12
xtreme1 359 天前
写了一大串, 然后被 ide 提示是个 true, 我相信大多数人都有这种经历(
|
13
popvlovs 359 天前
我不认同 OP 的一点是,人对“正确”或“错误”的判断( OP 所谓的逻辑直觉)并非是天然就有的,而是经过多次经验强化才会形成的
所以并不存在什么“这种判断应该是一种逻辑直觉”,因此“我没有这种直觉,我好奇这种直觉的缺失是怎么造成”就更无从谈起了 |
14
ptaooo 359 天前
有一说一,写的时候应该就有直觉是写
!A 且 !B 或者 A 或 B 吧。 |
15
visper 359 天前
一下就看出了啊。 比如,我们想从人群中找出一个人,只要他不是男人或者不是女人就行了。
|
16
yxd19 359 天前
@geelaw 我大概明白了,你之前说“不能推断任何事情”是说“编译器不能推断任何事情”吗?这样的话,针对你的三个点,编译器可以知道 complete 和 close 相不相等;有可能是提醒“x.getProcessStatus() != complete || x.getProcessStatus() != close”恒为真因此跟 scopes 是否非空没关系;倒是认为两次 getProcessStatus()结果一样确实比较武断。但这里输出的应该是个 info 啊 note 之类的,所以可能宁滥勿缺?我也不知道是啥语言。
|
17
GuuJiang 359 天前 via iPhone
德摩根律秒了
|
18
shyling 359 天前
没觉得有什么逻辑直觉。而是你这个 b1 你就没想好它是个什么东西,那后面的 lambda 你又怎么去写对。
|
21
LLaMA2 358 天前
x.getProcessStatus() != complete || x.getProcessStatus() != close
如果你的 getProcessStatus 某个时刻只能是多个状态中其一的话, 那么你这个条件必定是成立的。 因为你的状态不可以叠加,那么 x.getProcessStatus() != complete x.getProcessStatus() != close 必定有一个是 true , || 的时候有一个为 true ,不用多想,true !!!! |
22
dumbbell5kg OP @ye4tar 请问不可叠加是什么意思?
|
23
dumbbell5kg OP @cleanery 一下就被你说明白了
|
24
dumbbell5kg OP |
25
dumbbell5kg OP 这个问题不应跟代码扯上关系,其实我问的就是“数字 a !=1 或者数字 a !=2”表达式恒为 true 这个逻辑
非常抱歉造成的困扰 |
26
LLaMA2 355 天前
@dumbbell5kg “数字 a !=1 或者数字 a !=2”
这个数字只会有一种情况啊, 他总不能即是 1 又是 2 吧, 只有他即是 1 又是 2 的时候 才是 false , 所以我说他不能叠加,任何时候 a 只能是其一! |