SO上也有类似问题。
有时,当我们进行编程时,我们会发现某些特定的控制结构对我们非常有用,但是在我们的编程语言中并不能直接使用。
您认为哪些替代控制结构是组织计算的有用方法?
这里的目标是获得有关代码结构的新思考方式,以改善分块和推理。
您可以创建一个现在不可用的理想语法/语义,或者在现有的编程语言上引用一个鲜为人知的控件结构。
答案应该为新的编程语言或增强实际语言提供思路。
认为这是集思广益,所以发布您认为是疯狂的主意,但在某些情况下可行。
这是关于命令式编程的。
SO上也有类似问题。
有时,当我们进行编程时,我们会发现某些特定的控制结构对我们非常有用,但是在我们的编程语言中并不能直接使用。
您认为哪些替代控制结构是组织计算的有用方法?
这里的目标是获得有关代码结构的新思考方式,以改善分块和推理。
您可以创建一个现在不可用的理想语法/语义,或者在现有的编程语言上引用一个鲜为人知的控件结构。
答案应该为新的编程语言或增强实际语言提供思路。
认为这是集思广益,所以发布您认为是疯狂的主意,但在某些情况下可行。
这是关于命令式编程的。
Answers:
好,这是一个有趣的问题。
我还希望有一个else
while和for循环的通用表,用于第一次测试条件不成立的情况:
while (condition) {
// process
}
else {
// condition was never true
}
这样可以避免重新计算条件或将其存储在变量中。
为什么不将一些答案混为一谈呢?
while (expr) {
// Executed every iteration, unless first{} is present.
// May be explicitly called rest{} if you like first{} to come first.
// Blocks may return results, and consequently be used in expressions.
return expr;
} first {
// Executed only on the first iteration.
} pre {
// Executed before every iteration.
} post {
// Executed after every iteration.
} catch (oops) {
// All blocks are implicitly try{}ed if followed by a catch{}.
} finally {
// Executes after the block completes, regardless of exceptions.
} else {
// Executed if the loop body or rest{} never executes.
} never {
// Executes only when a client is present.
} drop (bad, worse), // Explicitly ignore certain exceptions.
until (expr); // Here, have a post-body condition, too.
使用命令性语言的可扩展的通用流控制构造语法将非常有用且有趣。在此之前,我只能使用Lisp或其他东西。
seventh { ... }
。
控制结构作为功能。
我想for
,if
,else
,while
,等是功能,而不是特殊的结构。
我想return
,try/except
并goto
成为延续的衍生物。
当然,这与特定的控制结构关系不大,而与总体上看控制结构(控制结构的元)的方式有关。
for
,if
,else
,和while
作为功能让我推断参数的功能需要,以表现与原来一样的结构懒洋洋地执行。有能力执行延迟执行会很好。
return
,异常等。但是现在,如果有需要,专家级程序员的工具箱中将提供功能强大的附加工具。此外,恕我直言的语言不应该“沉迷”。语言应具有支持不断增长的专业知识和CS知识增长的能力。
链接的文章绝对是关于Donald Knuth的N + 1/2 Loops的。用C / C ++ / Java表示:
for (;;) {
get next element;
if (at the end) break;
process the element;
}
这对于读取文件中的行或字符,测试是否达到EOF并进行处理非常有用。我很习惯看到这种模式for(;;)..if(..)break;
,这对我来说是惯用的。(在我读过Knuth的文章之前,该文章已在《Literate Programming》一书中转载,以前曾经是“ wtf?”。)
Knuth建议使用以下关键字loop/while/repeat
:
loop:
S;
while C:
T;
repeat
其中S
和T
是一系列零个或多个语句的占位符,并且C
是布尔条件。如果没有S
语句,则将是while循环,如果没有T
语句,则将是do循环。
可以通过允许零个或多个while C
子句来泛化此构造本身,使其非常适合于表示无限循环,然后表示一些罕见的条件,需要进行两次检查。
在同一篇文章中,Knuth提出了一种信令机制,该机制将是抛出/捕获异常的本地版本(作为使用goto的替代方法)。
为了我?我希望Java支持尾部调用优化,以便我可以根据需要表达任何常规控件结构。
更新:我忘了提到许多C / C ++ / Java程序员在以下情况下通过使用嵌入式分配来解决这一问题while
:
while ((c = getc(f)) != -1) {
T;
}
从Knuth的构建体使用术语,这是允许的时,S
并且C
可以组合成一个单一的表达。有些人不愿看到上面的嵌入式分配,而其他人不愿意看到的break
在for (;;)
上面。但是,当S
和C
不能合并时(例如,当S
有多个语句时),这for (;;)
是不重复代码的唯一选择。另一种选择是简单地复制S
代码:
S;
while (C) {
T;
S;
}
Knuth的loop/while/repeat
替代方案似乎要好得多。
repeat-until
循环。
do while ... loop until
-前置条件和后置条件都是可选的,我(大概)记得在一个循环中同时使用它们。对于您的中间条件,有Ada exit when ...;
。这样做的主要优点if ... break;
是,您可以编写一次exit loopname when ...;
退出多个(但不一定是全部)嵌套循环的退出。也可能比该中断更明显。
BCPL语言具有一个valueof
表达式,可用于将一系列语句转换为单个表达式:
foo(a, b, valueof {some series of statements; resultis v});
哪里some series of statements
可以是任何东西,并且整体valueof
评估为v
。
在Java中,当您需要计算用于调用this()
or 的参数时super()
(这不需要在其之前发生任何事情),这可能很方便。当然,您可以只编写一个单独的方法,但是如果您需要为上下文传递许多局部值,那可能会很麻烦。
如果您可以使用final
所需的变量,则可以valueof
使用匿名内部类在Java中进行操作:
foo(a, b, new Object(){String valueof(){
String v ...; some series of statements; return v;}}.valueof());
({ statement1; statement2; ...; result-expr; })
。我在其他地方也看到过类似的照片,但是我不记得在哪里。不过,可能都是从BCPL复制而来的。
unless(condition) {
// ...
}
与以下功能相同:
if(!condition) {
// ...
}
repeat {
// ...
} until(condition)
与以下功能相同:
do {
// ...
} while(!condition)
unless
。
另一方面,我希望看到对编程语言中的迭代器的更好支持。特别是,当您想配对两个集合时:
for (String s, Integer i : stringsSet, integersSet) {
// use the pair (s, i)
}
某些动态语言可能已经具有此功能,或者可以通过库和宏轻松支持,但是我认为这符合您的问题。
如果这两个集合的大小不同,则可能会引发异常,或者您可能会else
在循环后使用一个信号告知大小有所不同。
自然,您可以将其概括为三个或三个以上的列表。
更新:在可迭代对象之间进行笛卡尔积也是有用的:
for (String s, Integer i : stringsSet * integersSet) {
// use the pair (s, i), each s with each i
}
这只不过是嵌套循环:
for (String s : stringsSet) {
for (Integer i : integersSet) {
// use the pair (s, i), each s with each i
}
}
我有点担心,在这里提供的两种表示法之间,对的数量存在O(n)和O(n ^ 2)的差异,只改变了一个字符。
for a, b, c in itertools.product(iter1, iter2, iter3):
给您延迟评估的笛卡尔积。那是什么?您是否还想要给定迭代器的排列和组合?itertools.permutations
,itertools.combinations
。
有所谓的“ Dijkstra的环路”(也称为“ Dijkstra的保护环路”)。它是在“防护命令语言”(GCL)中定义的。您可以在上述Wikipedia文章的第6章重复:do中找到有关其语法和语义的一些信息。
如今,我实际上已经知道一种直接支持这种控制结构的编程语言。它是Oberon-07(PDF,70 KB)。它以while语句的形式支持“ Dijkstra的循环”。看一下9.6节。以上PDF中的while语句。
WHILE m > n DO m := m – n
ELSIF n > m DO n := n – m
END
附言:这是我的答复的副本。
具有内置回溯功能的图标样式表达式。
Python获得了很多Icon生成器的好处-并且在IMO中,它们做得更好。原则上,回溯只是一种异常抛出,但这是表达的简单性,大致相当于...
x = (a / b) else c;
处理失败案例,例如被零除。
Icon发疯的地方-没有返回布尔值的比较运算符。比较总是成功或触发了回溯,还有一些其他语义问题,我现在正拼命地记住这一点……好吧,我们只能说它可能比被遗忘更受压抑。
我一直认为他们应该有一个if
没有其他部分的表达式- if (condition, success-value)
某种事情,如果条件返回false则回溯-并删除奇怪的比较。
编辑,我记得-很明显。与两个参数的比较成功或失败-它不计算要返回的新值。所以,当它成功,有什么不就回来?答案-参数之一。但是,如果您编写a > b
,则返回的逻辑参数是- a
或b
?如果您b < a
改为写呢?我认为它总是返回正确的论点,这与任何东西一样有意义,但对于我来说,它通常通常仍然是错误的论点。
这只是一个一般的想法和语法:
if (cond)
//do something
else (cond)
//do something
also (cond)
//do something
else
//do something
end
还始终评估条件。ELSE照常工作。
它也适用于情况。也许这是消除break语句的好方法:
case (exp)
also (const)
//do something
else (const)
//do something
also (const)
//do something
else
//do something
end
可以理解为:
switch (exp)
case (const)
//do something
case (const)
//do something
break
case (const)
//do something
default
//do something
end
我不知道这是否有用或简单易懂,但这只是一个例子。
goto return ...;
语句的内容,使意图显式地进行尾部调用,因此,如果编译器无法进行迭代,则可能会出错。
无缝线程分支,其语法类似于函数,但是在单独的线程中执行,并且无法访问最初尚未传递给它的数据。
branch foo(data, to, be, processed){
//code
return [resulting, data]
}
调用分支时,它将立即返回一个句柄。
handle=foo(here, is, some, data)
句柄可用于检查任务是否完成。
handle.finished() //True if the execution is complete
如果在执行完成之前请求结果,则主线程将简单地等待。
[result, storage]=handle.result()
这不会涵盖更高级的多线程方案,而是提供一种开始容易地利用多个内核的简便方法。
handle.finished()
测试,但是对于90%的并行编程任务来说spawn
,这sync
就是您所需要的。
if (cond)
//do something
else (cond)
//do something
else (cond)
//do something
first
//do something
then
//do something
else (cond)
//do something
else
//do something
end
如果三个条件中的任何一个被评估为true,则FIRST和THEN块运行。FIRST块在条件块之前运行,然后THEN在条件块运行之后运行。
在FIRST和THEN语句之后的ELSE条件或最终写操作与这些块无关。
它可以读为:
if (cond)
first()
//do something
then()
else (cond)
first()
//do something
then()
else (cond)
first()
//do something
then()
else (cond)
//do something
else
//do something
end
function first()
//do something
return
function then()
//do something
return
这些功能只是一种阅读形式。他们不会创建范围。它更像是来自Basic的gosub / return。
讨论的实用性和可读性。
有时我发现自己编写了一个循环,该循环在第一次迭代中需要做一些不同的事情。例如,显示<th>标签而不是<td>标签。
我用布尔标志来处理这种情况。像这样:
first = true
while (some_condition)
if (first)
do_something
first = false
else
do_something_else
first
在大多数情况下,每次迭代都为假时,检查每次迭代的值似乎很愚蠢。
我想有一个循环选项,可以在第一次迭代时指定一个不同的循环体。不需要单独的变量。编译后的代码也不需要,因为生成的代码将具有两个主体,一个主体用于第一次迭代,另一个主体用于其余迭代。
print(out, first "<th>" then "<td>")
if (!first) gimme-a-comma ();
同一件事。但是,我会有一个异议-如果将其适当包装,最终会遇到诸如Python字符串连接方法之类的问题-但是通常您需要基本模式,因此不必经常重写底层循环。
if (!first)
,但微优化程序可能会引起分支预测异议。
if (!first)
并让优化的编译器确定循环主体是否足够小,以至于展开和摆脱first
是净赢。
[复制自我自己在stackoverflow上的答案]
ignoring
-忽略某些代码块中发生的异常。
try {
foo()
} catch {
case ex: SomeException => /* ignore */
case ex: SomeOtherException => /* ignore */
}
使用忽略的控件构造,您可以将其编写得更简洁明了:
ignoring(classOf[SomeException], classOf[SomeOtherException]) {
foo()
}
[Scala在util.control软件包的标准库中提供了此(以及许多其他异常处理控制结构)。]
try..catch
块是一回事。它迫使您识别错误并故意忽略它;在全局忽略下抛出大量代码可能会导致抛出这些异常时引发问题,并导致不良的编程习惯。
try
块,不同之处在于它列出了捕获到的异常并在前面而不是以后忽略。这甚至可能是可读性方面的优势-例如,即使读者在阅读打开的调用之前,也让读者知道丢失的文件不是错误。
代替:
switch(myEnum) {
case MyEnum.Val1: do1(); ...
case MyEnum.Val2: do2(); ...
....
使用Python或现在的C#方法进行:
action = val2func[myEnum]
action()
Scala具有许多新功能。
最后,可以扩展诸如Clojure之类的语言以提供额外的功能。
我有两个想法。
通常,我发现自己在重复做自己catch
。通过提取方法可以在一定程度上有所帮助,但是如果方法很短或不值得使用,则会导致不必要的混乱。因此,嵌套catch
块会很好:
try {
// Save something
} catch (Exception e) {
// Something we do for all Exceptions
catch (ProcessingException e) {
// Something we do for all Processing exceptions
catch (DBExcpetion e) {
// DBExceptions are a subclass of ProcessingException
}
catch (BusinessRuleException e) {
// BusinessRuleExceptions are also a subclass of ProcessingException
}
}
// Something we do after specific sub class Exceptions
}
在Web编程中,我也经常发现自己经常做这样的事情(这不是真实的示例,因此请不要分析虚构的案例):
Account a = getSavedAccount();
if (a == null) {
a = getAccountFromSessionId();
}
if (a == null) {
a = getAccountFromCookieId();
}
if (a == null) {
a = createNewAccount();
}
在Javascript中(嗯,ECMAScript,也许还有我不熟悉的其他语言),因为任何值都可以作为条件进行评估,||
所以可以提供帮助。
var a = getAFromLocation1() || getAFromLocation2() || default;
我真的很喜欢它的外观,并希望有更多的语言(尤其是服务器端的某些语言)支持它。(PHP可以将任何条件作为条件求值,但可以将整个条件表达式转换为布尔值而不是保留值。我不了解Python或Ruby。)在大约三种情况下,它可能会变得笨拙,但是如果有更多情况,超过三种情况,您的软件设计可能也很差。
x if c else y
的语法,所发生的一大原因是因为使用这些语义进行了大量表达||
和&&
人巧妙地马车。IIRC的常见情况是一个值(例如零),该值对于被视为的应用程序有效false
,因此被丢弃,因此使用了无效的后备。但是,请参阅我的回答WRT图标编程语言,它可以具有类似的表达式get1() else get2() else default
。
通用交换机上面已经说过:
switch(x){
predicate1:
dosomething();
predicate2:
dosomethingelse();
}
在Haskell中:
switch' :: a -> [(a -> Bool, b)] -> b
switch' a [] = undefined
switch' a (f,b):xs = if f a
then b
else switch' a xs
在C#中,我想对switch () { ... }
这些表达式使用simple ,但可以扩展:
switch (value)
{
// string-based operators:
case begins "Maria": // to catch Maria Carey
break;
case ends "Washington": // to catch George Washington
break;
case like "ph": // to catch Phil, Phillip, Sophie
break;
case between "Aaron" and "April": // to catch all names between
break;
// use non-static variables in case expression:
case Dao.GetDefaultBabyName():
break;
// continuable cases without breaking
case "John":
bonus = 25;
case "Peter":
salary = 500;
break;
// jumps between cases
case "Aleron":
// do something
break;
case "Bella":
// do something
jump "Aleron";
break;
}
等等。用数字或其他类型相同(支持IComparable
,IConvertible
...)
这可能会使我的代码更加简洁易读。
正如@Macneil所说,这是一个有趣的问题。
我(谦虚地咳嗽)发现的我最喜欢的异常控制结构是微分执行。
它有一定的用途。对我而言,绝大多数用于编程用户界面,这是维护冗余数据对应关系的更普遍问题的一个实例。一方面,有应用程序数据,另一方面,有UI控件,需要保持一致。这听起来像是“绑定”,但实际上还有很多。
通常我用C或C ++中的宏来实现它。在C#中,我必须通过手动扩展语句来做到这一点。那很痛苦,但是行得通。
一旦我用Lisp宏实现了它,那么它就很干净了。程序员方面不需要谨慎。如果我费心编写一个完整的解析器,然后生成所有正确的东西,那么我可能会用其他任何结构化语言做同样的事情。那是一个很大的项目,但我还没有做到。
像“传统的”控制结构就是for
要控制工人,使他屈从于执政的资本主义精英的腐败意识形态。这就是为什么我使用类似的替代控制结构的原因ph0r
。就像for
,但是更加激进:您不会ph0r
穿西装打领带,不会喷出一些公司BS。 ph0r
保持真实,伙计。
与权威对抗!
最简单的for
循环
for(100)
{
//Will run for 100 times
}
for(i)
{
//Will run for i times while i must be a positive integer
}
for(i as a)
{
//Will run for i times while i must be a positive integer
//and a is the incremental loop variable starting from 0 and
//scoped within the loop
}
for(i as a=2)
{
//Will run for i times while i must be a positive integer
//and a is the incremental loop variable starting from 2 and
//scoped within the loop
}