Answers:
您的问题尚不清楚,但是观察者模式似乎就是您正在寻找的东西http://en.wikipedia.org/wiki/Observer_pattern
在语法方面,很多语言都有when
关键字,但是我不知道有任何语言以您的描述方式使用它。
“ X发生时,Y发生”模式是面向方面编程的核心:您无需将线性处理程序定义为将某些条件挂接到处理程序中(也称为“订阅”一个“事件”)。这种编程在GUI应用程序中很普遍,其中该程序的核心例程是事件分发程序。
一些语言具有广泛的语法功能,可以通过语言构造来提供这种机制。一个示例是带有其委托和事件的C#:
// 'when btnOK is clicked, run HandleOKClick'
btnOK.Clicked += this.HandleOKClick;
其他语言使用OOP构造(观察者模式,事件侦听器等; Java中的示例)(我的Java有点生锈,因此可以随意编辑):
Foobar f = this;
btnOK.registerClickHandler(
new ClickHandler {
public void handleClick(Event e) {
f.handleOKClick(e);
}
});
还有一种方法是使用普通的旧回调。JavaScript中的示例:
var btnOK = $('btnOK');
btnOK.click(handleOKClick);
COMEFROM最初是在笑话汇编语言说明列表(如“ CMFRM”)中看到的。R. Lawrence Clark于1973年在Datamation文章中对此进行了详细说明,该文章是针对Edsger Dijkstra的信《致有害的声明》而写的。COMEFROM最终以更深奥的“计算COMEFROM”以深奥的编程语言INTERCAL的C-INTERCAL变体实现。还提供了Fortran建议,用于“ assigned COME FROM”和“ DONT”关键字(以补充现有的“ DO”循环)。
2004年4月1日,Richie Hindle发布了针对Python编程语言的GOTO和COMEFROM的实现。尽管已在愚人节发布,并且不打算供认真使用,但语法有效,实现完全正常。
Tcl语言具有对变量的跟踪,这些变量允许在设置变量(或读取或删除变量,但在这里不太重要)时执行任意代码。该任意代码可以轻松地包括对表达式求值并执行某些代码(如果有)。主要约束是,尽管您可以对局部变量执行此操作,但由于它们的寿命通常很短,因此通常不是很有用,因此此类操作通常仅限于全局变量和名称空间变量。(Tcl没有闭包。)
但是,如果要执行此操作,则应小心。虽然您在形式上并没有正式的问题(在执行身体的过程中禁用了跟踪),但它仍然是编写非常不清楚的代码并引起很多混乱的好方法。将其与循环变量(而不是用于调试)一起使用也是一个非常糟糕的主意,因为性能影响可能非常明显。
举例说明(基于上面链接的手册页中的代码)。
set foo 1
set bar 2
proc doMult args {
global foo bar foobar
set foobar [expr {$foo * $bar}]
}
trace add variable foo write doMult
trace add variable bar write doMult
doMult
从那时起,任何时候$foo
或$bar
成为新整数的任何时间都$foobar
成为两者的乘积。自动地。
Tcl还允许设置要在其他类型的触发器上运行的代码,例如执行命令,删除命令,计时器,套接字上可用的数据等。添加了Tk库后,它可以扩展为包括一大套以及GUI事件。可以说Tcl实际上是一种非常强烈的面向事件的语言(即使您可以轻松编写从未使用任何这些功能的代码)。
是的,Perl中有一个关键字,作为语句修饰符:
say 'Well done!' when 'A';
这也是switch语句的一部分:
given ($foo) {
when (/^abc/) { $abc = 1; }
when (/^def/) { $def = 1; }
when (/^xyz/) { $xyz = 1; }
default { $nothing = 1; }
}
switch
对我的声明。(上面有黄铜旋钮,但再次是 Perl…)
case
一个switch
声明。就像在Ada中一样。
难道这(COMEFROM
在维基百科中描述语句)算什么?
摘要:
COMEFROM与GOTO大致相反,它可以将执行状态从代码中的任意点转移到COMEFROM语句。代码中发生状态转移的点通常作为COMEFROM的参数给出。传输是在指定传输点的指令之前还是之后进行的,取决于所使用的语言。根据所使用的语言,引用同一个出发点的多个COMEFROM可能无效,不确定,以某种已定义的优先级执行,甚至导致并行执行或并行执行(如线程插入)所示。
您是否正在寻找具有同步或异步when语句的语言?
对我来说,这听起来像是一个事件(/订阅/回调)模式。
例如
conditionOwner.Condition += listener.WhenCondition
每当条件所有者通知条件已经发生时,侦听器将执行WhenCondition()。
您可以将绑定模式与转换器一起使用,该转换器检查多个输入变量的状态(更改时)并计算条件,然后将侦听器的输入属性绑定到输出,并在更改输入时起作用。
从语言开始,例如.NET(即C#)已内置了同步订阅(事件),而其Reactive Extensions(RX)添加了异步订阅。
描述听起来像一个数据库触发器,旨在等待某种情况然后执行。
从维基百科:
数据库触发器是响应于数据库中特定表或视图上的某些事件而自动执行的过程代码。触发器主要用于保持数据库中信息的完整性。例如,当将一个新记录(代表一个新工人)添加到employees表中时,还应该在税收,休假和薪水表中创建新记录。
您要说的是语法,而不是structure。when
在执行有限数量的逻辑,然后执行该when
语句,然后循环并再次执行该逻辑(无限循环)的系统中,您实际上只能有一个这样的语句。
例如,Windows编程通常是“基于事件的”。订阅按钮Click
事件实质上意味着“单击时执行此操作”。但是,幕后情况是消息处理循环。当用户单击按钮时,Windows将消息发送到应用程序,并且应用程序中的消息处理循环运行适当的事件处理程序。
例如,如果您在C#中使用事件,则可以在没有消息循环的情况下执行此操作,但局限性在于必须提前声明事件,因此您不能编写监视when
任何类型事件的人工声明。州。您必须等待特定的事件。
为了在冯·诺依曼体系结构中获得这种行为,您必须运行某种无限循环,该循环在每次运行适当代码的循环中都将检查所有条件。在内部,您只会得到一大堆if
/ then
或switch
语句。大多数桌面应用程序和Web程序员都会呕吐,如果他们看到这样的结构,那么只有将其包装在某种形式的语法糖(例如Windows事件模型)中,它才真正可口(即使这是在幕后进行)。
另一方面,如果您查看嵌入式固件开发,实时执行人员或工业控制器领域,则这种编程模型非常普遍。例如,如果您有一个实时程序,则可能要表达:
outputA = input1 && input2
该代码易于理解(因为它是声明性的)。但是,要使其工作,您必须在紧密的循环中执行它。您outputA
每次循环都要重新评估。许多台式机或Web程序员都不喜欢这样做,因为它效率低下。对于他们来说,您唯一需要重新评估的时间outputA
是何时input1
或input2
更改。他们宁愿看到更像您所描述的内容:
when input1 changes
evaluateOutputA()
when input2 changes
evaluateOutputA()
evaluateOutputA()
outputA = input1 && input2
现在,如果这是您想要的(并且我个人不喜欢这个想法),并且您的目标是效率,那么您仍然必须问自己处理器在幕后正在做什么。显然,仍然存在某种循环,每次都会将输入状态与以前的输入状态进行比较,并在每次更改时执行适当的代码。因此,实际上它的效率较低,更难以阅读和维护。
另一方面,如果input1
更改时必须执行的工作很重要,则您的when
子句可能有意义。在PLC中,这种指令称为“上升沿检测”。它保存input1
循环中最后一次的状态,这次将其与值进行比较,如果最后一个状态为false且此状态为true,则执行逻辑。
如果您没有冯·诺依曼架构,那么游戏就会改变。例如,如果您正在VHDL中对FPGA进行编程,则在编写时:
outputA = input1 && input2
(...或任何适当的VHDL语法),然后实际上将FPGA连接起来,input1
并input2
连接到AND门的输入,并将AND门的输出连接到outputA
。因此,代码不仅易于理解,而且还可以与所有其他逻辑并行执行,并且效率很高。
在谈论以五种IEC-61131-3语言之一编程的工业控制器(如PLC或PAC)时,典型的情况是这种布置:
这是内置于系统架构中的,因此,您只需编写:
outputA = input1 && input2
...,它将连续循环执行。
这些机器中也有中断程序。这些更像when
是您在说的对操作员的硬件级别支持。所述硬件中断是外部事件执行一些代码的手段。例如,当网卡说它正在等待数据时,处理器通常必须立即读取该数据,否则您将耗尽缓冲区空间。但是,对于需要钩住真正的硬件中断的时间,我怀疑包括语言关键字是否值得。您将只能使用CPU输入引脚,并且看起来您想测试内部程序状态。
因此,在传统语言中(没有无限循环的紧密循环),您必须问一个问题:“评估代码何时运行”?
如果您写:
when A do
launchNukes()
...并且假设A
是一个任意布尔表达式,您如何知道何时重新评估该表达式?天真的实现意味着您必须在每次写入单个内存后重新评估它。您可能会认为可以缩小范围,但是请考虑以下因素:
when systemTime > actionTime do
launchNukes()
请注意,systemTime
它总是在变化(每次阅读时,您都会得到一个不同的数字)。这意味着您所有when
子句的条件部分都必须不断重新评估。这几乎是不可能的(只需考虑一秒钟,如果您的条件表达式有副作用!)
when
在基于运行主程序的无限循环的体系结构中,您只能有一条语句(如您所描述的),然后when
在此循环中条件从false变为true时执行该语句。尽管此体系结构在嵌入式和工业设备中很常见,但在通用编程语言中并不常见。
该AspectJ语言有一个加入点模型,其是用于处理正是这种情况的解决方案。
AspectJ中的Join-Point是Java程序中的动态事件,该事件在程序执行时发生。连接点示例为:(1)调用方法;(2)执行一个方法;(3)调用构造函数;(4)执行构造函数;(5)设置一个字段;或(6)字段被访问。
然后,您可以创建这些连接点的集合,称为切入点。然后可以按照通常的集合论方法将切入点合并,补充和相交。其他切入点可以以变量的值/类型为条件(例如,“仅当x为正时”,“仅当设置的值是该类型的子类时”)和程序的状态(“当调用此方法,但仅当此其他方法在此线程的堆栈上时[意味着该方法间接调用了该方法]“)。
一旦所有这些切入点都描述了程序中的事件,就可以使用AspectJ来建议这些事件。您可以选择在事件发生之前(before
建议),事件发生之后(after
建议)或代替事件发生(around
建议)来做某事。
Around
建议对于在程序中添加缓存特别有用:当执行某些方法时,在表中查找是否已经执行了相同的计算,如果已执行,则使用缓存的版本。使用AspectJ,它是如此的轻巧和富于表现力,您可以在代码中的数百个不同点上进行这样的缓存实验,以查找缓存是否以及在何处添加值。
面向方面编程之外的许多人认为AOP主要是关于“日志记录”的。您可以使用AspectJ来处理日志,并且它做得很好(“当调用此程序包中的所有公共方法时,在此日志文件中记录,以及它们的结果/错误结果是什么”)。但是AspectJ还有很多东西,包括一个用来模拟动态范围的聪明技巧,称为蠕虫孔图案 [请参见幻灯片23及以下]。
在AOP之外,您还在谈论基于事件的编程,其中包括[如其他人所指出的]观察者模式。解决方案之间的区别是:(1)如何检测到状况;(二)表达条件的;(3)如何将执行代码绑定到事件。
如何使用“通知/等待”似乎与此相似:
我们已经提到Java等待/通知机制本质上是一种在线程之间进行通信的方法。简而言之,想法如下:
- 一个或多个线程坐在等待信号;
- 出现另一个线程并通知等待的线程(即通过信号“唤醒/唤醒”)。
根据上下文,有些结构可能与此接近,但是您确实必须澄清您的问题。
该元素用于根据一系列测试确定一个操作过程。每个测试都在一个元素内完成。如果测试成功,则执行元素的主体。如果没有测试失败,则可以使用一个元素来指定默认操作:
XSLT“何时”是一个条件语句,比if 更像是一个开关。但是,最初的问题中“何时”的含义并没有真正弄清楚。
我经常在Sitecore CMS中使用XSLT,在其中我用于呈现内容,因此在某些情况下可以在GUI环境中使用它。
if
,即使它不是if
您在编程语言中可以找到的过程类型。(我将XSLT看作是一种特定的数据处理语言,而不是一种通用的编程语言-我看不到您使用XSLT构建桌面GUI)
您要的是所谓的反应式编程。
这是一种编程范例,其中变量了解它们已分配的表达式,并且只要表达式的组成部分发生更改,变量就会通过重新评估表达式做出反应,并可能触发依赖关系链下的其他类似的重新评估。 。
通常,这种反应性行为是通过巧妙地使用观察者模式来实现的,其中反应性值将自身注册为侦听触发值重新评估的一组事件的侦听器。
就我所知,还没有一种编程语言完全包含反应式编程的核心,但是许多语言中有很多库以一种或另一种方式提供了反应式编程的好处。
大多数数据绑定框架都可以视为反应式编程的实现。
有一篇很好的论文叫做“ 弃用观察者模式 ”,它可能比我以前能解释的要好得多。
Lisp(以及它的许多Dialetc,包括Scheme)具有:
(when (> 2 1) 'do-something)
计算为do-something
和:
(when nil 'other-thing)
计算结果为nil
或同等学历。
when
更像是if,而不是OP偶然描述的观察者模式。
听起来您正在寻找条件变量,这些条件变量使线程可以休眠直到某些谓词变为真。
Boost实现了C ++的功能,Apache Portable Runtime实现了C的功能。在Common Lisp中,您将使用bordeaux-thread
的make-condition-variable
。
如果您认为Drools是一种语言,那就可以。
一个例子:
rule "Rule 08 - Debit"
when
AccountingPeriod( $start : start, $end : end )
$cashflow : AllocatedCashflow( $account : account, $date : date <= $end, $amount : amount, type==TypedCashflow.DEBIT )
not AccountingPeriod( start < $start)
then
$account.setBalance($account.getBalance()-$amount);
retract($cashflow);
end
Perl 6可以使用tap
以下方式直接处理信号:
signal(SIGINT).tap: {
note "Took { now - INIT now } seconds.";
exit;
}
for 0, 1, *+* ... * {
sleep 0.5;
.say;
}
而Powershell可以使用带有try / finally块的运行循环来处理它:
$Start_Time = (Get-date).second
Write-Host "Type CTRL-C to Terminate..."
$n = 1
Try
{
While($true)
{
Write-Host $n
$n ++
Start-Sleep -m 500
}
}
Finally
{
$End_Time = (Get-date).second
$Time_Diff = $End_Time - $Start_Time
Write-Host "Total time in seconds"$Time_Diff
}
可以预期使用trap
:
package require Expect
proc sigint_handler {} {
puts "elapsed time: [expr {[clock seconds] - $::start_time}] seconds"
set ::looping false
}
trap sigint_handler SIGINT
set start_time [clock seconds]
set n 0
set looping true
while {$looping} {
puts [incr n]
after 500
}
参考文献
您可能会看看OPS5语言。它的程序是作为一组条件编写的。当满足条件时,将执行相应的操作。这些动作可以修改状态,这可能导致其他条件得到满足。尽管它不使用when
关键字,但它实际上是通过在“满足”条件时执行操作来工作的。从这里:
OPS5程序包括一个声明部分和一个生产部分,在声明部分定义了基本数据结构,在生产部分定义了处理数据的规则。
OPS5程序通过将工作内存元素与生产内存中的规则进行匹配并触发(执行)最匹配的规则来执行。Match-Select-Execute循环继续进行,直到程序显式停止或直到没有规则与工作内存匹配为止。
90年代初上大学时,我不得不用这种语言写过一段简单的文字冒险。这很有趣,但是我不确定它对于大多数桌面或移动任务有多大用处。不过,在后端环境中这可能很有意义。
Haskell有一个。但这不是一个特殊的构造,只是另一个功能http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:when
select case table1.col1 when 1 then 'Y' else 'N' end as col1_yn from ...
。另外:msdn.microsoft.com/en-us/library/dd233249.aspx基本上,我会使用Google代码搜索来搜索“何时”。