是否存在“何时”声明?[关闭]


12

是否有可以处理“何时”案件的语言或语言功能?也就是说,只要某个条件变为真,无论在任何范围或上下文中,都可以指定执行额外的代码?

请注意,这与simple有所不同if,后者必须在特定范围内并明确编写。该when子句几乎类似于if在其后的程序执行中适用于所有情况的。


1
SQL Server :select case table1.col1 when 1 then 'Y' else 'N' end as col1_yn from ...。另外:msdn.microsoft.com/en-us/library/dd233249.aspx基本上,我会使用Google代码搜索来搜索“何时”。
工作

5
@Job:那是一个子句,不是声明。
Ben Voigt

2
您的意思是像在Verilog中一样?
2011年

2
需要更多描述...非常广泛的问题。
WernerCD 2011年

2
这个问题正在讨论在这里上元。
亚当李尔

Answers:


25

您的问题尚不清楚,但是观察者模式似乎就是您正在寻找的东西http://en.wikipedia.org/wiki/Observer_pattern


1
是的,我问的似乎是它的本机实现。我还想指出下面有关响应式编程的有趣论文,“弃用观察者模式”(无链接,CTRL + F组合键)。从理论上说,一条when语句将在程序执行期间的任何时候满足条件(无论如何实现)都运行一个代码块,并且至少减轻了我不得不执行该条件的工作。观察者模式由我自己决定。
WindScar 2011年

15

在语法方面,很多语言都有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);

15

还没有人提到INTERCALCOMEFROM

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的实现。尽管已在愚人节发布,并且不打算供认真使用,但语法有效,实现完全正常。


7
...而不得不宠坏它!:-)
Stephen C


2
@BenVoigt:您的答案在发布时不包含“ Intercal”或“ COMEFROM”。
DeadMG

2
@DeadMG:我的答案最初的版本中包含“ en.wikipedia.org/wiki/COMEFROM ”。
Ben Voigt

2
@BenVoigt:这不算在内。
DeadMG

6

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实际上是一种非常强烈的面向事件的语言(即使您可以轻松编写从未使用任何这些功能的代码)。


4

像事件处理一样?

代替func()处理事件

你说什么时候做活动

或者,也许是对特定变量的回调?


绝对听起来像一个事件。
Ton Plomp 2011年

4

是的,Perl中有一个关键字,作为语句修饰符:

say 'Well done!'        when 'A';

这也是switch语句的一部分:

given ($foo) {
    when (/^abc/) { $abc = 1; }
    when (/^def/) { $def = 1; }
    when (/^xyz/) { $xyz = 1; }
    default { $nothing = 1; }
}

5
我不了解Perl,但是对我来说,“何时”看起来更像是“如果”……我认为问题的意思是“何时”的“何时<event> <action>”类型。
ShdNx 2011年

1
闻起来像switch对我的声明。(上面有黄铜旋钮,但再次 Perl…)
Donal Fellows

实际上,这是case一个switch声明。就像在Ada中一样。
mouviciel 2011年

4

难道这(COMEFROM在维基百科中描述语句)算什么?

摘要:

COMEFROM与GOTO大致相反,它可以将执行状态从代码中的任意点转移到COMEFROM语句。代码中发生状态转移的点通常作为COMEFROM的参数给出。传输是在指定传输点的指令之前还是之后进行的,取决于所使用的语言。根据所使用的语言,引用同一个出发点的多个COMEFROM可能无效,不确定,以某种已定义的优先级执行,甚至导致并行执行或并行执行(如线程插入)所示。


6
我知道你来自哪里。
Pubby的

6
-1为没有摘要的链接;linkrot可能发生。
雨果

5
@Ben-无论如何,如果您不愿意写超过3个单词,那么答案会更好。
BlackJack

3
@BenVoigt:在这种情况下,您可以粘贴整个链接,而不是将其隐藏在“ this”之后。
Marjan Venema

1
@BenVoigt:我的意思是,如果您粘贴整个链接而不是将其隐藏在“ this”之后,则要搜索的单词将立即显示在您的答案文本中,而不是仅当您将鼠标悬停在链接上方时...另外,我碰巧同意BlackJack和Hugo的观点,即主要是链接的答案至少应简要概述在那里可以找到的内容。它有助于确保StackExchange可以站立自己的两只脚,即使链接确实腐烂了也是如此。
Marjan Venema

3

您是否正在寻找具有同步或异步when语句的语言?

对我来说,这听起来像是一个事件(/订阅/回调)模式。

例如

conditionOwner.Condition += listener.WhenCondition

每当条件所有者通知条件已经发生时,侦听器将执行WhenCondition()。

您可以将绑定模式与转换器一起使用,该转换器检查多个输入变量的状态(更改时)并计算条件,然后将侦听器的输入属性绑定到输出,并在更改输入时起作用。

从语言开始,例如.NET(即C#)已内置了同步订阅(事件),而其Reactive Extensions(RX)添加了异步订阅。


3

描述听起来像一个数据库触发器,旨在等待某种情况然后执行。

从维基百科:

数据库触发器是响应于数据库中特定表或视图上的某些事件而自动执行的过程代码。触发器主要用于保持数据库中信息的完整性。例如,当将一个新记录(代表一个新工人)添加到employees表中时,还应该在税收,休假和薪水表中创建新记录。

http://en.wikipedia.org/wiki/Database_trigger


3

您要说的是语法,而不是structurewhen在执行有限数量的逻辑,然后执行该when语句,然后循环并再次执行该逻辑(无限循环)的系统中,您实际上只能有一个这样的语句。

例如,Windows编程通常是“基于事件的”。订阅按钮Click事件实质上意味着“单击时执行此操作”。但是,幕后情况是消息处理循环。当用户单击按钮时,Windows将消息发送到应用程序,并且应用程序中的消息处理循环运行适当的事件处理程序。

例如,如果您在C#中使用事件,则可以在没有消息循环的情况下执行此操作,但局限性在于必须提前声明事件,因此您不能编写监视when任何类型事件的人工声明。州。您必须等待特定的事件。

为了在冯·诺依曼体系结构中获得这种行为,您必须运行某种无限循环,该循环在每次运行适当代码的循环中都将检查所有条件。在内部,您只会得到一大堆if/ thenswitch语句。大多数桌面应用程序和Web程序员都会呕吐,如果他们看到这样的结构,那么只有将其包装在某种形式的语法糖(例如Windows事件模型)中,它才真正可口(即使这是在幕后进行)。

另一方面,如果您查看嵌入式固件开发,实时执行人员或工业控制器领域,则这种编程模型非常普遍。例如,如果您有一个实时程序,则可能要表达:

outputA = input1 && input2

该代码易于理解(因为它是声明性的)。但是,要使其工作,您必须在紧密的循环中执行它。您outputA每次循环都要重新评估。许多台式机或Web程序员都不喜欢这样做,因为它效率低下。对于他们来说,您唯一需要重新评估的时间outputA是何时input1input2更改。他们宁愿看到更像您所描述的内容:

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连接起来,input1input2连接到AND门的输入,并将AND门的输出连接到outputA。因此,代码不仅易于理解,而且还可以与所有其他逻辑并行执行,并且效率很高。

在谈论以五种IEC-61131-3语言之一编程的工业控制器(如PLC或PAC)时,典型的情况是这种布置:

  1. 读取输入并存储在内存中
  2. 执行主程序
  3. 将存储器中的输出写入实际输出
  4. 转到步骤1

这是内置于系统架构中的,因此,您只需编写:

outputA = input1 && input2

...,它将连续循环执行。

这些机器中也有中断程序。这些更像when是您在说的对操作员的硬件级别支持。所述硬件中断是外部事件执行一些代码的手段。例如,当网卡说它正在等待数据时,处理器通常必须立即读取该数据,否则您将耗尽缓冲区空间。但是,对于需要钩住真正的硬件中断的时间,我怀疑包括语言关键字是否值得。您将只能使用CPU输入引脚,并且看起来您想测试内部程序状态。

因此,在传统语言中(没有无限循环的紧密循环),您必须问一个问题:“评估代码何时运行”?

如果您写:

when A do
    launchNukes()

...并且假设A是一个任意布尔表达式,您如何知道何时重新评估该表达式?天真的实现意味着您必须在每次写入单个内存后重新评估它。您可能会认为可以缩小范围,但是请考虑以下因素:

when systemTime > actionTime do
    launchNukes()

请注意,systemTime它总是在变化(每次阅读时,您都会得到一个不同的数字)。这意味着您所有when子句的条件部分都必须不断重新评估。这几乎是不可能的(只需考虑一秒钟,如果您的条件表达式有副作用!)

结论

when在基于运行主程序的无限循环的体系结构中,您只能有一条语句(如您所描述的),然后when在此循环中条件从false变为true时执行该语句。尽管此体系结构在嵌入式和工业设备中很常见,但在通用编程语言中并不常见。


3

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)如何将执行代码绑定到事件。


2

如何使用“通知/等待”似乎与此相似:

我们已经提到Java等待/通知机制本质上是一种在线程之间进行通信的方法。简而言之,想法如下:

  • 一个或多个线程坐在等待信号;
  • 出现另一个线程并通知等待的线程(即通过信号“唤醒/唤醒”)。

根据上下文,有些结构可能与此接近,但是您确实必须澄清您的问题。

XSLT中还有一个“何时”语句

该元素用于根据一系列测试确定一个操作过程。每个测试都在一个元素内完成。如果测试成功,则执行元素的主体。如果没有测试失败,则可以使用一个元素来指定默认操作:


XSLT“何时”是一个条件语句,比if 更像是一个开关。但是,最初的问题中“何时”的含义并没有真正弄清楚。

我经常在Sitecore CMS中使用XSLT,在其中我用于呈现内容,因此在某些情况下可以在GUI环境中使用它。


XSLT when听起来更像是一个if,即使它不是if您在编程语言中可以找到的过程类型。(我将XSLT看作是一种特定的数据处理语言,而不是一种通用的编程语言-我看不到您使用XSLT构建桌面GUI)
Marjan Venema

2

您要的是所谓的反应式编程

这是一种编程范例,其中变量了解它们已分配的表达式,并且只要表达式的组成部分发生更改,变量就会通过重新评估表达式做出反应,并可能触发依赖关系链下的其他类似的重新评估。 。

通常,这种反应性行为是通过巧妙地使用观察者模式来实现的,其中反应性值将自身注册为侦听触发值重新评估的一组事件的侦听器。

就我所知,还没有一种编程语言完全包含反应式编程的核心,但是许多语言中有很多库以一种或另一种方式提供了反应式编程的好处。

大多数数据绑定框架都可以视为反应式编程的实现。

有一篇很好的论文叫做“ 弃用观察者模式 ”,它可能比我以前能解释的要好得多。


我的问题的最佳答案之一。很棒的纸。
2011年

1
随时将其标记为“接受”(眨眼,眨眼,点头,点头)
Roland Tepp

我本来打算发布它,但是很高兴您击败了我,并且写了一个比我要好的得多的答案。响应式编程非常棒(这是一种用功能语言构建UI的好方法),但有点深奥。
迪洪·杰维斯

1
@RolandTepp无耻的自我提升,是吗?我很欣赏你。+1
尼尔

0

Lisp(以及它的许多Dialetc,包括Scheme)具有:

(when (> 2 1) 'do-something)

计算为do-something和:

(when nil 'other-thing)

计算结果为nil或同等学历。


2
Lisp when更像是if,而不是OP偶然描述的观察者模式。
ocodo 2011年

0

我知道这样的语句仅用于错误处理。例如,BASIC ON ERROR ...或SQL * PLUSWHENEVER SQLERROR ...

对于仲裁条件,将需要非常聪明的编译器或相当昂贵的蛮力(在每条语句之后检查)以捕获条件变为真的确切时刻。


0

它是数据流语言的功能,例如硬件描述语言(Verilog和VHDL)。

除此之外,我还可以想到Ada及其异常处理机制:触发异常处理程序会引发when一些异常。



0

如果您认为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

0

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
}

参考文献


0

自从我看了这些书已经很久了,所以我很可能会误会。

我记得,PL / I和BASIC都具有“ ON”语句。在PL / I中,该概念是“ ON DO”。在BASIC中,它是“ ON”,其中语句通常是GOSUB。在这两种语言中,只要指定条件成立,就会执行关联的语句。

您今天不想这样做。编译器基本上必须做大量工作,以弄清楚条件何时何地变为真,以便它可以在那时生成测试。一旦进入关联的处理程序,您就不会真正知道您来自哪里,因此您必须弄清楚是什么原因使您到达那里,并且您可能不想回到原来的位置。


0

您可能会看看OPS5语言。它的程序是作为一组条件编写的。当满足条件时,将执行相应的操作。这些动作可以修改状态,这可能导致其他条件得到满足。尽管它不使用when关键字,但它实际上是通过在“满足”条件时执行操作来工作的。从这里

OPS5程序包括一个声明部分和一个生产部分,在声明部分定义了基本数据结构,在生产部分定义了处理数据的规则。

OPS5程序通过将工作内存元素与生产内存中的规则进行匹配并触发(执行)最匹配的规则来执行。Match-Select-Execute循环继续进行,直到程序显式停止或直到没有规则与工作内存匹配为止。

90年代初上大学时,我不得不用这种语言写过一段简单的文字冒险。这很有趣,但是我不确定它对于大多数桌面或移动任务有多大用处。不过,在后端环境中这可能很有意义。



-1

在大多数OOP语言中,可以生成一个额外的线程,并将其作为上下文:

    while (!value)
{
}

//Execute code

-1

好吧,您可以编写一堆并行线程,每个并行线程都会查询各自的条件。我想那将是一个性能很差的应用程序,但这是可能的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.