码农

Icon编程语言手册 简略翻译版 第四章

2024-11-06  本文已影响0人  FSS_Sosei

第4章 控制结构

4.1 {e1; e2; ; en }

大括号用于包围表达式序列。除最后一个表达式外,每个表达式都按顺序求值,以产生最多一个值。无论成功还是失败,都将继续并计算序列中的下一个表达式。最后一个表达式en将生成周围上下文允许的尽可能多的值。例如:

    every {writes(" ",1 to 5);writes(" ",6 to 10)}

会输出

    1 6 7 8 9 10

大括号中表达式序列用的分号分隔,也可换成换行,比如上面的可改写成:

    every

    {

        writes(" ",1 to 5)

        writes(" ",6 to 10)

    }

4.2 every do

我们已经看过了every表达式的简单形式:

    every e1

另一种形式是:

    every e1 do e2

也就是说对于e1的每一个值,求e2的值。

• e1生成它能生成的所有值。

• 每次e1生成一个值,就去计算e2。

• 表达式e2可能成功也可能失败。

• 每次计算e2时最多生成一个值。

• 当e1失败时,every-do表达式失败。

它看起来更像是带有do的传统语言中的循环,它更直观。对于break和next表达式,它的行为是不同的,见第4.11节和第4.12节讨论。

“Every-expressions”是表达式,可以放在其他表达式中。这个表达式不产生返回值。和&fail一样,它是终止于失败而不返回值。但是,如果它们由break表达式退出,则可以返回值。参见4.11节

4.3 if then else

写成多行形式:

    if e1

    then

        e2

    else

        e3

if表达式的行为与传统语言中的if语句非常相似,但有以下区别:

• 评估表达式e1以确定其成功或失败。如果e1成功,if表达式的行为类似于e2;如果e1失败,它的行为就像e3一样。

• 表达式e1是生成器的话,e1最多只能生成一个值用于if判断后就终止了。

• e2或e3可以根据上下文的需要生成任意多的值。

与其他语言一样,有一种版本省略了else表达式:

    if e1 then e2

如果省略else子句并且e1失败,则整个if表达式失败。

4.4 目标导向的评估

看下面的程序,求某个直角三角形的边长,其边长之和不小于1000且不大于2000个单位

例8 求一个直角三角形

    procedure main()

        local i,j,m,n

        if

            i:=1 to 2000 &

            j:=i to 2000 &

            n:=i*i+j*j &

            m:=integer(sqrt(n)) &

            m*m = n &

            1000 <= i+j+m <= 2000

        then

            write(i," ",j," ",m)

    end

这是一个以目标为导向的求值示例。目标用测试m*m = n & 1000 <= i+j+m <= 2000表示。计算可以被看作是试图生成达到目标的边i和边j。

在其他编程语言中,您可能必须编写几个嵌套循环才能找到这样的三角形。(顺便说一下,它找到的边是33,544和545。)一旦找到了它,就必须跳出多重循环终止查找。

4.5 case of { }

case表达式的行为类似于其他编程语言中的case或switch语句。一般形式:

    case e1 of {

        e2 : e3

        e4 : e5

        ...

        e2n : e2n+1

        default : e2n+2

    }

等价于

    {

        (tmp := e1)\1 &

        if tmp===(e2) then e3

        else if tmp===(e4) then e5

        ...

        else if tmp===(e2n) then e2n+1

        else e2n+2

    }

相等比较的比较运算符是全称相等检验===。如果给定两个数字,则执行数值检验;如果两个字符串,一个字符串测试。对于其他类型的对象,它测试它们是否为相同的对象。

4.6 while do

一般形式:

    while e1 do e2

while表达式类似于其他编程语言中的while语句。它与every表达式的不同之处在于,它每次迭代最多从e1生成一个值。

简单的来说:

• 计算e1

• 如果e1成功,则计算e2

• e2可能成功也可能失败

• 每次迭代最多从e1生成一个值,最多从e2生成一个值

• 一旦e2被求值,它将重新开始对e1求值

• e1失败则while do表达式失败

有一个没有do子句的版本:

    while e

它从一开始就重复计算e,直到失败。

例如,这里有一个文件复制程序。它把输入复制到输出。如果您从键盘上运行它,它会回写您键入的每一行。

例9 文件复制

    procedure main( )

        while write(read( ))

    end

read过程每次读取一行输入,并在输入完成时失败。

文件副本不能使用every表达式。读取过程不是生成器。当控制向前移动时,每次输入一行,它将返回一行,但在回溯过程中不能恢复;回溯将回溯过去。

这是一个小工具程序,用于在 C 中为bit位置创建定义宏。你可以输入一系列标识符,它将为每个标识符创建一行 #define。这使得每个标识符都成为一个不同的2的幂。也就是说,它将每个标识符设置为不同bit位置的掩码。

例10 定义位

    procedure main()

        i := 1

        while x := read() do

        {

            write("#define ",x," ",i)

            i := i+i

        }

    end

4.7 not

一般形式:

    not e

如果表达式e失败,“not e”将成功;如果e成功,则“not e”失败。

如果“not e”成功(e失败),它将返回“&null”。

因为not是一元操作符,所以它的优先级比任何二元操作符都高。您几乎总是需要将其操作数用圆括号括起来。

4.8 全真逻辑用全否形式写出来

Icon对表达式进行评估,试图找到一些方法使它们成功。成功意味着至少有一种方法可以使它成功。例如,假设我们想知道列表L中是否有两个元素相等。我们可以这样写:

    i:=1 to *L-1 & j:=i+1 to *L & L[i]===L[j]

有时候你想知道某件事是否对所有人都成立,而不是对某个人成立。没有办法直接在Icon中编写。你不得不求助于双重否定。

某事物对所有人都为真,当且仅当没有人对它不为真。

假设我们希望找出一个列表中的所有元素是否都相等。如果所有元素彼此相等,它们就等于第一个元素,所以如果有任何元素不等于第一个元素,那么它们就不都相等。我们可以把测试写成

    not (i:=2 to *L & L[1]~===L[i])

4.9 until do

一般形式:

    until e1 do e2

until表达式的行为类似于

    while not ( e1 ) do e2

简单的来说:

• 计算e1

• 如果e1失败,则计算e2

• e2可能成功也可能失败

• 每次迭代最多从e2生成一个值

• 一旦e2被求值,它将重新开始对e1求值

• 它最多从e1生成一个值,因为一旦e1成功,它就会失败

有一个没有do子句的版本:

    until e

它从一开始就反复求值,直到成功为止。

例如,考虑下面的程序来生成最多100,000的斐波那契数。斐波那契数的序列定义如下:前两个斐波那契数为1;后面的每一个数字都是前面两个斐波那契数的和。

例11 使用until编写斐波那契数

    procedure main()

        local i,j

        i:=1

        j:=1

        until i>100000 do

        {

            write(i)

            i+:=j

            i:=:j

        }

    end

4.10 repeat

一般形式:

    repeat e

将反复计算表达式e。除非通过break、return、suspend或fail等显式退出,否则它永远不会终止。

4.11 break

break表达式用于退出任何类型的循环(every、while、until、repeat)。break有两种形式,单独break和包含表达式的break,如下:

    break

    break expression

对于简单的break,会直接退出当前循环。与循环失败退出不同的是,使用break退出会成功返回表达式的值。如果表达式不存在,则返回&null。

你可以这样写:

    if every {... break ...}

    then exited_by_break()

    else exited_normally()

"break expression"形式会退出循环,并返回表达式生成的值。实际上,表达式会表现得好像不在循环中。如果表达式包含break或next,它们会应用于包含该循环的下一层循环。

例12 使用repeat编写斐波那契数

    procedure main()

        local i,j

        i:=1

        j:=1

        repeat

        {

            write(i)

            i+:=j

            i:=:j

            if i>100000 then break

        }

    end

4.12 next

一般形式:

    next

表达式next使它所在的循环开始下一次迭代。

如果它在every表达式中

    every e1 do e2

它立即导致回溯到表达式e1。

如果它在“while”或“until”之内

    while e1 do e2

    until e1 do e2

会再次计算表达式e1。

如果它在“重复”范围内

    repeat e1

它又开始计算e1。

上一篇下一篇

猜你喜欢

热点阅读