这是因为 do 机制并不关心(幸运的是)最里面的代码是否真的引用了(某些)循环变量。
不管最里面的代码如何,你总是得到 3*5=15 个值:
λ>
λ> xs1 = do { i <- [1..5] ; j <- [2..4] ; return i }
λ> xs1
[1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
λ>
λ> xs2 = do { i <- [1..5] ; j <- [2..4] ; return 9 }
λ> xs2
[9,9,9,9,9,9,9,9,9,9,9,9,9,9,9]
λ>
λ> xs3 = do { i <- [1..5] ; j <- [2..4] ; return (i,j) }
λ> xs3
[(1,2),(1,3),(1,4),(2,2),(2,3),(2,4),(3,2),(3,3),(3,4),(4,2),(4,3),(4,4),(5,2),(5,3),(5,4)]
λ>
λ> length xs1
15
λ> length xs2
15
λ> length xs3
15
λ>
据我所知,这是 Haskell 与 C、C++、Fortran、Python 共享的完全标准行为......
一个 C++ 等效示例:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> vi{1,2,3,4,5};
std::vector<int> vj{2,3,4};
for (int i: vi)
for (int j: vj)
std::cout << i << ", ";
std::cout << std::endl;
return EXIT_SUCCESS;
}
C++ 输出:
$ ./a.out
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5,
$