一个逻辑直觉的问题

356 天前
 dumbbell5kg
Boolean b1 = scopes.stream()
                .anyMatch(x -> x.getProcessStatus() != complete || x.getProcessStatus() != close);

我写了这么一段代码,编译器告诉我这是有问题的,大家可以先想一下编译器提示了什么,下面有答案和我的疑问。















这个表达式是恒为 true 的,我是编译器告诉我后,想了一会才确认这个问题,我觉得奇怪的是这种判断应该是一种逻辑直觉,我没有这种直觉,我好奇这种直觉的缺失是怎么造成的?

2159 次点击
所在节点    程序员
26 条回复
AoEiuV020JP
356 天前
啊这,我第一眼也没发现,似乎脑补成了&&,
cleanery
356 天前
x.getProcessStatus() != complete || x.getProcessStatus() != close
两个不等, 或
只有一种情况才是 false
就是 x.getProcessStatus() == complete && x.getProcessStatus() == close 被满足的时候
cleanery
356 天前
你缺失的应该是等效替代的直觉, 看到这种表达式,我一般是去掉否定的同时逆转 或/与
判断条件尽量不要用否定, 因为人是没有否定直觉的。 如果用否定,也尽量让条件简单清晰

举个例子, 不要想小白兔--- 不要想小白兔--- 不要想小白兔--- 不要想小白兔
laqow
356 天前
交集是与,并集是或,但语言上与也可以是并集的意思
geelaw
356 天前
这段代码不能推断任何事情——都不知道 scopes 、x 、complete 、close 是什么!假设 scopes.stream() 是 sensible 的。

如果 scopes 是空集,则 anyMatch 当然永远是 false 。
如果 scopes 不是空集,那么 getProcessStatus() 可能有副作用,连续调用两次不一定返回相同的数值。
我们也不知道 complete 和 close 是不是相等。

如果假设 getProcessStatus() 无副作用,且 complete 和 close 不相等,那么 b1 的结果等于 scopes 是否是空,这依然是非平凡的,除非上文里编译器可以推断 scopes 非空。

培养逻辑直觉的第一步是放弃错误的直觉(也就是所谓的“想当然”)。
NoOneNoBody
356 天前
人类习惯“二选一”,好多多选题都习惯(潜意识)简化为“二选一”处理,这样可以结果单一化,从而达到问题简单化,便于思考。大部分时候确实效果不错,因为大部分情况下,多选的选择肢并非各向平均,往往大概率是走向两种最受关注的结果,其他就忽略了

例如很常见的例子,“排除他杀”,过半数人马上想到自杀

所以“全集”切割为多项,靠直觉往往难以完整覆盖,就是把分出来的各项不能重新拼合为原来的全集
yxd19
356 天前
@geelaw
1. 如果有人写了一个叫 getProcessStatus 的带副作用的函数,你可以打他。
2. 如果有人写了两个相等的叫 complete 和 close 的常量,你可以打他。
3. 如果有人用 xs.anyMatch(x -> true)判断 xs 是否为空,你可以打他。
mohulai
356 天前
啥玩意 别人又不知道你 ProcessStatus 只有 complete close 两个状态
geelaw
356 天前
@yxd19 #7 我不确定你为什么会认为名字类似 getProcessStatus 的方法是无副作用的,举个非常自然的例子,如果 x 对象基于操作系统级别的进程,那么 getProcessStatus 很可能每次调用的时候都会检查操作系统级别的进程是否结束,并根据操作系统级别的进程的结束状态(还在运行、以 0 退出、以 1 退出、以其他返回值退出)决定返回值。调用操作系统级别检查进程状态的 API 相当于某种同步 (synchronization) 操作,永远属于有副作用操作。

从您打人的条件来看,似乎光是把 complete/close 写成小写就可以发动您打人的动作了?实际上,同一个数值具有多个不同的同类型枚举名字的状况不少见。我想没有什么人在“正经”的程序里用 xs.anyMatch(x -> true) 判空,但不代表它的行为不是如此。

另外您似乎忘了:当下的主题是形式逻辑,不是编程最佳实践。
yxd19
356 天前
@geelaw 是在聊形式逻辑,可是不添加足够多的前提假设怎么聊形式逻辑呀。比如要讨论“去买一斤橘子,如果有西瓜就买一个”这句话的逻辑,当然要首先靠常识(“编程最佳实践”)把这个不严密的说法改写成(相对)严密的说法(去买一斤橘子;如果有西瓜就买一个西瓜),来显露出形式逻辑,然后把重点放到逻辑上,而不是宣称这句话可能有两种不同的理解方式啊。

我想你也知道 lz 只不过是突然发现「天不是甲或天不是乙」恒为真这件事,你当然可以认为这件事是初等的、没啥可讨论的,但是也没必要把讨论拉到 lz 在这个帖子中并不关注的另一部分。这对于其他人理解 lz 的重点没啥好处。
geelaw
356 天前
@yxd19 #10 我并不是这么理解的,楼主的话的意思显然是编译器认为 b1 是恒为 true ,这才是让我惊讶的点——因为我以为编译器不会追踪集合是否是空。

此外就是这段代码看起来像 Java ,而我以为 Java 编译器不会做这么多的检查,尤其是 x 的静态类型上的 getProcessStatus 非常可能不是密封(最终)方法,从而不能假设是无副作用,对它静态分析非常困难。

但总之,我的第一条回复的另一层含义是楼主说话应该把上下文说清楚。

另外怎么突然用清朝微积分语言(?
xtreme1
356 天前
写了一大串, 然后被 ide 提示是个 true, 我相信大多数人都有这种经历(
popvlovs
356 天前
我不认同 OP 的一点是,人对“正确”或“错误”的判断( OP 所谓的逻辑直觉)并非是天然就有的,而是经过多次经验强化才会形成的
所以并不存在什么“这种判断应该是一种逻辑直觉”,因此“我没有这种直觉,我好奇这种直觉的缺失是怎么造成”就更无从谈起了
ptaooo
356 天前
有一说一,写的时候应该就有直觉是写
!A 且 !B
或者
A 或 B
吧。
visper
356 天前
一下就看出了啊。 比如,我们想从人群中找出一个人,只要他不是男人或者不是女人就行了。
yxd19
356 天前
@geelaw 我大概明白了,你之前说“不能推断任何事情”是说“编译器不能推断任何事情”吗?这样的话,针对你的三个点,编译器可以知道 complete 和 close 相不相等;有可能是提醒“x.getProcessStatus() != complete || x.getProcessStatus() != close”恒为真因此跟 scopes 是否非空没关系;倒是认为两次 getProcessStatus()结果一样确实比较武断。但这里输出的应该是个 info 啊 note 之类的,所以可能宁滥勿缺?我也不知道是啥语言。
GuuJiang
356 天前
德摩根律秒了
shyling
356 天前
没觉得有什么逻辑直觉。而是你这个 b1 你就没想好它是个什么东西,那后面的 lambda 你又怎么去写对。
LUO12826
356 天前
@mohulai #8 仔细想想,即使有更多状态楼主说的也成立的
mohulai
355 天前

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1004434

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX