V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dumbbell5kg
V2EX  ›  程序员

一个逻辑直觉的问题

  •  1
     
  •   dumbbell5kg · 120 天前 · 1912 次点击
    这是一个创建于 120 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Boolean b1 = scopes.stream()
                    .anyMatch(x -> x.getProcessStatus() != complete || x.getProcessStatus() != close);
    
    

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















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

    第 1 条附言  ·  118 天前
    这个问题不应跟代码扯上关系,其实我问的就是“数字 a !=1 或者数字 a !=2”表达式恒为 true 这个逻辑,
    非常抱歉造成的困扰。
    26 条回复    2024-01-02 10:20:55 +08:00
    AoEiuV020JP
        1
    AoEiuV020JP  
       120 天前
    啊这,我第一眼也没发现,似乎脑补成了&&,
    cleanery
        2
    cleanery  
       120 天前   ❤️ 1
    x.getProcessStatus() != complete || x.getProcessStatus() != close
    两个不等, 或
    只有一种情况才是 false
    就是 x.getProcessStatus() == complete && x.getProcessStatus() == close 被满足的时候
    cleanery
        3
    cleanery  
       120 天前
    你缺失的应该是等效替代的直觉, 看到这种表达式,我一般是去掉否定的同时逆转 或/与
    判断条件尽量不要用否定, 因为人是没有否定直觉的。 如果用否定,也尽量让条件简单清晰

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

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

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

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

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

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

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

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

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

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

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

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

    如果你的 getProcessStatus 某个时刻只能是多个状态中其一的话,

    那么你这个条件必定是成立的。

    因为你的状态不可以叠加,那么

    x.getProcessStatus() != complete
    x.getProcessStatus() != close

    必定有一个是 true , || 的时候有一个为 true ,不用多想,true !!!!
    dumbbell5kg
        22
    dumbbell5kg  
    OP
       118 天前
    @ye4tar 请问不可叠加是什么意思?
    dumbbell5kg
        23
    dumbbell5kg  
    OP
       118 天前
    @cleanery 一下就被你说明白了
    dumbbell5kg
        24
    dumbbell5kg  
    OP
       118 天前
    @geelaw
    @yxd19
    我的问题,忘了说是 Java 语言,用的开发软件是 IDEA ,而且是开发软件提示的,并不是编译器,提问的时候没多想。
    dumbbell5kg
        25
    dumbbell5kg  
    OP
       118 天前
    这个问题不应跟代码扯上关系,其实我问的就是“数字 a !=1 或者数字 a !=2”表达式恒为 true 这个逻辑
    非常抱歉造成的困扰
    LLaMA2
        26
    LLaMA2  
       116 天前
    @dumbbell5kg “数字 a !=1 或者数字 a !=2”

    这个数字只会有一种情况啊,
    他总不能即是 1 又是 2 吧,
    只有他即是 1 又是 2 的时候 才是 false ,
    所以我说他不能叠加,任何时候 a 只能是其一!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2747 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 10:15 · PVG 18:15 · LAX 03:15 · JFK 06:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.