【问题标题】:How is Prolog `shift`/`reset` like other languages?Prolog `shift`/`reset` 与其他语言有何不同?
【发布时间】:2022-08-21 00:48:39
【问题描述】:

我在 Haskell here 中找到了一个移位重置分隔延续的示例:

resetT $ do
    alfa
    bravo
    x <- shiftT $ \\esc -> do
       charlie
       lift $ esc 1
       delta
       lift $ esc 2
       return 0
    zulu x

这将:

  1. 执行alfa

  2. 执行bravo

  3. 执行charlie

  4. x绑定到1,从而执行zulu 1

  5. resetT 的末尾掉下来,然后跳回到esc 1 之后

  6. 执行delta

  7. x绑定到2,从而执行zulu 2

  8. resetT 的末尾掉下来,然后跳回到esc 2 之后

  9. 逃离resetT,导致它产生0

    我不知道如何使用 SWI-Prolog 的 shift/1reset/3 编写等效代码。

    下面的代码是我的尝试。输出是一样的,但看起来很乱而且倒退,我觉得我在滥用Ball 来获得类似于Haskell 示例中的esc 1esc 2 的东西。另外,我不确定如何处理return 0

    % not sure about this...
    example :-
      reset(step, ball(X), Cont),
      ( writeln(\"charlie\"), X=1, call(Cont), fail
      ; writeln(\"delta\"), X=2, call(Cont)).
    
    step :-
      writeln(\"alfa\"),
      writeln(\"bravo\"),
      shift(ball(X)),
      format(\"zulu ~w~n\", X).
    

    我很困惑:Scheme/Haskell/ML-style shift-reset 和 Prolog shift-reset 看起来几乎是完全不同的东西!例如,您将 lambda 传递给 Haskell 的 shiftT,但您没有将目标传递给 Prolog 的 shift/1。

    Haskell 的\\esc -&gt; ... esc 1return 0 的Prolog 等价物在哪里? Prolog 的 Ballcall(Cont) 的 Haskell 等价物在哪里?

    我觉得上面 Haskell 示例的“正确”端口可以回答这些问题。

    标签: haskell prolog swi-prolog continuations delimited-continuations


    【解决方案1】:
    1. resetshift 运算符最初来自 Danvy; Filinski,1990. “Abstracting Control”。 Haskell 中的对应接口Control.Monad.Trans.Cont 符合原始语义,some type restrictions 除外。 SWI-Prolog 中的定界延续接口并不完全是原来的resetshift。它们与Felleisen,1988's prompt and controlSitaram’s fcontrol and run operators 的关系更密切。

    2. 通常,将分隔的延续程序从 Haskell 转换为 Prolog 并不困难。您的示例中的困难在于它使用不同的值两次调用相同的延续esc。例如,

      example :-
        reset(step, ball(X), Cont),
        X=1, call(Cont),
        X=2, call(Cont).
      

      在第一个call(Cont) 之后,X 已经绑定到1,不能重新绑定到2

      TomSchrijvers' advice 是使用 copy_term/2 使用新的统一变量创建延续的副本(是的,延续也是 SWI-Prolog 中的术语!),因此与您的示例等效的 Prolog 是

      example(X) :-
        reset(step, Ball, Cont),
        copy_term(Cont+Ball, Cont1+Ball1),
        copy_term(Cont+Ball, Cont2+Ball2),
        writeln("charlie"),
        ball(X1) = Ball1,
        X1=1, reset(Cont1, _, _),
        writeln("delta"),
        ball(X2) = Ball2,
        X2=2, reset(Cont2, _, _),
        X=0.  
      
      step :-
        writeln("alfa"),
        writeln("bravo"),
        shift(ball(X)),
        format("zulu ~w~n", X),
        shift(ball(X)).
      
      ?- example(X).
      alfa
      bravo
      charlie
      zulu 1
      delta
      zulu 2
      X = 0.
      

      更详细的讨论,见https://swi-prolog.discourse.group/t/naming-clarification-about-delimited-continuation-reset-3-and-shift-1

    【讨论】:

      【解决方案2】:

      对于某些情况,可行的替代方案是
      使用可以让步的引擎。他们甚至有时
      更快,至少对于 SWI-Prolog 的一些测试,

      我们比较了用
      shift/1 与用
      engine_yield/1:

      /* shift/1, warm run, 22.08.2022 */
      ?- time(run_state(fib(28), 0, S)).
      % 9,770,334 inferences, 2.437 CPU in 2.861 seconds (85% CPU, 4008342 Lips)
      S = 514229 .
      
      /* engine_yield/1, warm run, 22.08.2022 */
      ?- time(run_state(fib(28), 0, S)).
      % 3,599,612 inferences, 1.109 CPU in 1.177 seconds (94% CPU, 3244721 Lips)
      S = 514229 .
      

      这是完整的源代码,以使其可重现,
      两种解决方案都发布在 SWI-Prolog 讨论中:

      shift/1 解决方案在这里:

      http://www.rubycap.ch/gist/shiftreset.pl

      engine_yield/1 解决方案在这里:

      http://www.rubycap.ch/gist/state2.pl

      【讨论】:

        猜你喜欢
        • 2016-06-10
        • 2015-05-02
        • 2021-09-15
        • 1970-01-01
        • 2017-04-03
        • 1970-01-01
        • 1970-01-01
        • 2020-08-15
        • 2010-12-17
        相关资源
        最近更新 更多