For循环

for循环（for loop）在电脑科学是一种程式语言的迭代陈述，能够让程式码反复的执行。

它跟其他的循环，如while循环，最大的不同，是它拥有一个循环计数器，或是循环变数。这使得for循环能够知道在迭代过程中的执行顺序。

## for 循环的种类

### 传统的 for 循环 for-loops

C语言中传统的for-loop包含三个部分：初始化、条件、递增，这三个部分都是可有可无的。

以Java为例：

```java
for (INITIALIZATION; CONDITION; AFTERTHOUGHT) 
{
    // Code for the for-loop's body goes here.
}
```

初始化是宣告（或者赋值）任何需要的变数的动作。如果你要使用多个变数，则变数的种类要一致。条件的部分则是检查是否离开这个循环，也就是让程式码往下执行。如果条件判断为假，则离开循环。递增在每跑一次循环都会重复执行一次。

在此以Java为例：

```java
for (int i=0; i<100; i++)   // Prints the numbers 0 to 99 (and not 100), each separated by a space.
{
    System.out.print(i);
    System.out.print(' ');
}
System.out.println();
```

### 使用指标的for循环

这种形式的for循环是大多数其他for循环的变革：他允许除了数字以外的计数方式。他通常用隐含或外显指标的方式呈现，而在此循环变数会依序表示。以下是一个代表性的例子(语言：Python)：

```python
for item in some_iterable_object:
    do Something
    do Something Else
```

### 矩阵化for循环

有一些语言支援比较特别的for循环，如同它可以同时处理所有的指标in parallel，像是在FORTRAN 95中的`for all`语法。

举例来说，在以下的for循环虚拟码片段，当计算`A(i)`的新的值，除了第一个(也就是 `i = 2`)，`A(i - 1)`的参照会得到新的值。

然而，在`for all` 版本，每个计算都会使用一开始的值，不会更改 `A`.

```
'''for'''     i := 2 : N - 1 '''do''' A(i) := [A(i - 1) + A(i) + A(i + 1)] / 3; '''next''' i;
'''for all''' i := 2 : N - 1 '''do''' A(i) := [A(i - 1) + A(i) + A(i + 1)] / 3;
```

和一般的for循环可能差距比较大。

## 应用范例

以c语言为例：

### 作为无穷循环

```C
for (;;)
   printf("just keep going on!");
```

这个程式码会不断的印出"just keep going on!"。

### 配合矩阵

矩阵赋值：

```C
for(int i=0;i<bound_of_matrix;i++)
   matrix[i] = i;
```

以上给予矩阵 matrix 依序从0到bound_of_matrix-1 的值。

### 巢状循环

就像巢穴一样，一层包覆一层，所以以下这个程式码一共会执行(bound_of_x)乘上(bound_of_y)次。

```C
for(int i=0;i<bound_of_x;i++)
   for(int j=0;j<bound_of_y;j++)
      matrix[i][j] = j;
```

## 常见的错误

### 无穷循环

这里指的是无意产生的无穷循环，容易导致当机。

以C语言为例：

```C
for (int i=0;i<10;i--)
   printf("confused");
```

### 超出界限

编译器会显示out of bound，通常是指尝试取矩阵界限外的值。

### 循环内的变数

循环内的变数在出循环之后，便无法使用。

## 发展概论

主要缘起为许多需要重复执行的程式码，而不一样的程式语言也会有不一样的语法型式。

### 1957: FORTRAN

在Fortran 的`DO` 循环 同等于for循环。

Fortran的 `DO` 循环语法为：

```FORTRAN
         DO label counter = first, last, step
         statements
  label  statement
  
```

接下来的两个例子做出来的结果等同于其他语言的三个参数的for循环。其中变数COUNTER被初始化为1，以1递增，并且到5的时候停下。

```FORTRAN
   DO 9, COUNTER = 1, 5, 1
     WRITE (6,8) COUNTER
8    FORMAT( I2 )
9  CONTINUE
```

Fortran 77 或之后的版本，也可能写成：

```FORTRAN
do counter = 1, 5
  write(*, '(i2)') counter
end do
```

如果递增为1，则递增的部分可以省略。例如：

```FORTRANfixed
* DO loop example.
       PROGRAM MAIN
         SUM SQ = 0
         DO 199 I = 1, 9999999
           IF (SUM SQ.GT.1000) GO TO 200
199        SUM SQ = SUM SQ + I**2
200      PRINT 206, SUMSQ
206      FORMAT( I2 )
       END
```

### 1958: Algol

Algol 在Algo158首次正式格式化。

### 1960: COBOL

COBOL在许多努力之下，在1959年终正式格式化。他使用PERFORM 动词，而PERFORM动词有很多功能，像是后来加上的＂结构化＂的语法，像是 END-PERFORM。忽略宣告和初始化变数的必要，类似for循环的语法为：

```COBOL
      PERFORM VARYING I FROM 1 BY 1 UNTIL I > 1000
             ADD I**2 TO SUM-SQ.
      END-PERFORM
```

如果PERFORM有TEST AFTER，这个循环的执行的结果会有点不同：循环内的程式会被执行至少一次。

### 1964: BASIC

BASIC 中的循环有时称为 for-next循环。

```freebasic
For I = 1 to 5;
 Print I;
Next I
```

### 1964: PL/I

由IBM公司在1950年代发明的第三代高级程式语言，有些类似PASCAL语言。

以下为PLI使用例：

```PLI
do counter = 1 to 5 by 1; /* "by 1" is the default if not specified */
  /*statements*/;
  end;
```

LEAVE 指令可以用来结束循环，像c语言的break，而ITERATE则像continue。

### 1968: Algol 68

Algol68 很类似现在的for语言了：

```Algol68
FOR i FROM 1 BY 2 TO 3 WHILE i≠4 DO ~ OD
```

### 1970: Pascal

```Pascal
for Counter := 1 to 5 do
  (*statement*);
```

### 1972: C/C++

```C
for (initialization; condition; increment/decrement)
    statement
```

### 1980: Ada

```ada
for Counter in 1 .. 5 loop
   -- statements
end loop;
```

### 1980: Maple

Maple有两种型式的for循环，一个是指标一定范围的值，另一个是指标一定大小的容器。

第一种：

```
'''for''' ''i'' '''from''' ''f'' '''by''' ''b'' '''to''' ''t'' '''while''' ''w'' '''do'''
    ''# loop body''
'''od''';
```

第二种：

```
'''for''' ''e'' '''in''' ''c'' '''while''' ''w'' '''do'''
    ''# loop body''
'''od''';
```

### 1982: PostScript

他的for循环 `[initial] [increment] [limit] { ... } for` 初始化一个内部的变数, 并且执行到他不大于限制的值(若递增为负则以此类推)。

```AppleScript
1 1 6 {STATEMENTS} for
```

### 1983: Ada 83 and above

```ADA
procedure Main is
  Sum_Sq : Integer := 0;
begin
  for I in 1 .. 9999999 loop 
    if Sum_Sq <= 1000 then
      Sum_Sq := Sum_Sq + I**2
    end if;
  end loop;
end;
```

### 1984: MATLAB

```MATLAB
for i = 1:5 
     -- statements
end
```

### 1987: Perl

```Perl
for ($counter = 1; $counter <= 5; $counter++) { # implictly or predefined variable
  # statements;
}
for (my $counter = 1; $counter <= 5; $counter++) { # variable private to the loop
  # statements;
}
for (1..5) { # variable impicitly called $_; 1..5 creates a list of these 5 elements
  # statements;
}
statement for 1..5; # almost same (only 1 statement) with natural language order
for my $counter (1..5) { # variable private to the loop
  # statements;
}
```

### 1988: Mathematica

```Ruby
Do[f[x], {x, 0, 1, 0.1}]
```

```Ruby
For[x= 0 , x <= 1, x += 0.1,
    f[x]
]
```

### 1989: Bash

```bash
*第一種
for i in 1 2 3 4 5
do
    # must have at least one command in loop
    echo $i  # just print value of i
done
```

```bash
*第二種
for (( i = 1; i <= 5; i++ ))
do
    # must have at least one command in loop
    echo $i  # just print value of i
done
```

### 1990: Haskell

```haskell
forM_ [1..5] $ \indx -> do statements
```

如果你想要用更正式的方式存 1..5的内容，一个比较官方的方式为：

```haskell
import Control.Monad as M

forLoopM_ :: Monad m => a -> (a -> Bool) -> (a -> a) -> (a -> m ()) -> m ()
forLoopM_ indx prop incr f = do
        f indx
        M.when (prop next) $ forLoopM_ next prop incr f
  where      
    next = incr indx    
```

并且可以这样使用：

```haskell
  forLoopM_ (0::Int) (< len) (+1) $ \indx -> do -- whatever with the index
```

### 1991: Oberon-2, Oberon-07, or Component Pascal

```Oberon2
FOR Counter := 1 TO 5 DO
  (* statement sequence *)
END
```

### 1991: Python

```Python
for counter in range(1, 6):  # range(1, 6) gives values from 1 to 5 inclusive (but not 6)
  # statements
```

### 1993: AppleScript

```AppleScript
repeat with i from 1 to 5
	-- statements
	log i
end repeat
```

### 1993: Lua

```Lua
for i = start, stop, interval do
     -- statements
end
```

这个程式码

```Lua
for i = 1, 5, 2 do
     print(i)
end
```

即会印出：

```Lua
1 3 5
```

### 1995: Java

```Java
for (int i = 0; i < 5; i++) {
    //perform functions within the loop;
    //can use the statement 'break;' to exit early;
    //can use the statement 'continue;' to skip the current iteration
}
```

### 1995: JavaScript

JavaScript 支援像是C语言的三个参数的循环，并且支援break和continue。

```JavaScript
for (let i = 0; i < 5; i++) {
    // ...
}
```

### 1995: PHP

```PHP
for ($i = 0; $i <= 5; $i++)
{
  for ($j = 0; $j <= $i; $j++)
  {
    echo "*";
  }
  echo "<br>";
}
```

### 1995: Ruby

```Ruby
for counter in 1..5
  # statements
end

5.times do |counter|  # counter iterates from 0 to 4
  # statements
end

1.upto(5) do |counter|
  # statements
end
```

### 1996: OCaml

请参考

```ocaml
 (* for_statement := "for" ident '='  expr  ( "to" ∣  "downto" ) expr "do" expr "done" *)

for i = 1 to 5 do
    (* statements *)
  done ;;

for j = 5 downto 0 do
    (* statements *)
  done ;;
```

### 1998: ActionScript 3

```actionscript3
for (var counter:uint = 1; counter <= 5; counter++){
  //statement;
}
```