Haskell初学者疑问:两种列表推导式写法为何不同?
两种列表推导式写法的差异解析
嘿,作为刚入坑Haskell函数式编程的新手,能琢磨列表推导式的不同写法已经很棒啦!先直接给你结论:在你当前的代码里(xs是[1..4]),这两种写法的输出结果是完全一致的,但如果换一组xs的值,两者就可能产生不同的结果——核心差异在于「重复元素的处理」。
第一种写法:两个推导式拼接(++)
你的第一版代码是把两个独立的列表推导式用++拼接起来:
listComprehension = [(a,b,c) | a <- xs, b <- xs, c <- ys, even c, c == a+b] ++ [(a,b,c) | a <- xs, b <- xs, c <- ys, even c, c == a-b] where xs = [1..4]; ys = [(-100)..100]
这相当于:
- 先找出所有满足
even c且c == a+b的三元组 - 再找出所有满足
even c且c == a-b的三元组 - 最后把这两个列表按顺序拼接
如果某个三元组同时满足c == a+b和c == a-b(比如当b=0时,a+b = a-b = a),那这个元素会在第一个推导式里出现一次,第二个里又出现一次,最终在结果列表里会有两个完全相同的副本。
第二种写法:单个推导式用||合并条件
第二版代码是把两个条件用逻辑或||合并到同一个推导式里:
listComprehension = [(a,b,c) | a <- xs, b <- xs, c <- ys, even c, c == a+b || c == a-b] where xs = [1..4]; ys = [(-100)..100]
这相当于:
- 一次性找出所有满足
even c,且**要么满足c=a+b,要么满足c=a-b**的三元组 - 哪怕某个三元组同时满足两个等式,它也只会被生成一次,不会重复出现在结果里
为什么你的例子里看不出差异?
因为你定义的xs = [1..4],b的取值是1到4,不存在b=0的情况。我们可以解一下c == a+b且c == a-b的条件:
a+b = a-b → 2b = 0 → b=0
而你的xs里没有0,所以不存在同时满足两个条件的三元组,因此两种写法的输出完全一致。但如果把xs改成[0..4],你就能看到差异了——比如当a=2,b=0,c=2(偶数)时,第一种写法会生成两次(2,0,2),而第二种只会生成一次。
总结
- 当不存在同时满足两个条件的元素时,两种写法等价
- 当存在同时满足两个条件的元素时,第一种写法会重复生成该元素,第二种不会
- 如果你的需求是「不允许重复元素」,第二种写法更简洁高效;如果需要保留重复(比如某些计数场景),第一种写法更合适
内容的提问来源于stack exchange,提问作者Marcel
相关产品推荐
相关产品推荐

