动态/静态范围与深/浅绑定(练习) [英] Dynamic/Static scope with Deep/Shallow binding (exercises)

查看:177
本文介绍了动态/静态范围与深/浅绑定(练习)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究动态/静态范围,使用深/浅绑定和手动运行代码来查看这些不同的作用域/绑定实际工作的方式。我读了这个理论,并尝试了一些示例练习,我发现的很简单(如这个这对动态范围非常有帮助)但是我很难理解静态范围的作用。



这里我发表了一个练习,以检查我是否得到正确的解决方案:



考虑以下程序以伪码编写:

  int u = 42; 
int v = 69;
int w = 17;
proc add(z:int)
u:= v + u + z
proc bar(fun:proc)
int u:= w;
fun(v)
proc foo(x:int,w:int)
int v:= x;
bar(add)
main
foo(u,13)
print(u)
end;

打印到屏幕的内容



a )使用静态范围?答案= 180



b)使用动态范围和深度绑定?答案= 69(u = 126的总和,但是是foo的本地v,对吗?)



c)使用动态范围和浅绑定?答案= 69(u = 101的总和,但是是foo的本地v,对吗?)



PS:如果你知道哪里,我正在尝试做一些这样的练习我可以找到这些类型的问题(最好与解决方案)请给链接,谢谢!

解决方案

您的词汇(静态) )范围是正确的。您的动态范围的答案是错误的,但如果我正在阅读您的解释,那是因为您在 u v ,而不是因为对如何深浅浅的绑定工作有任何真正的误解。 (我假设你的 u / v 混乱只是偶然的,而不是由于对价值观的一个奇怪的混淆与 foo 中的引用相比。)


a)使用静态范围?答案= 180


正确。


b)使用动态范围和深度绑定?答案= 69(对于你的总和= 126,但是是foo的本地v,对吗?)


你的括号解释是正确的,但你的答案是错误的: u 确实设置为 126 foo 确实本地化 v ,但是由于 main 打印 u 不是 v ,答案是 126


c)使用动态范围和浅绑定?答案= 69(对于u = 101而言,这是foo的本地v,对吗?)


您实际上是 97 42 + 13 + 42 ),但由于 bar 本地化 u ,答案是 42 。 (你的括号解释是错误的,你似乎已经使用全局变量 w ,这是 17 bar 的定义中解释语句 int u:= w ;但该语句实际上是指 foo 的局部变量 w ,其第二个参数是 13 main 打印 u ,而不是 v 。)






对于词汇范围,它很漂亮通过将伪代码翻译成具有词汇范围的语言,便于检查您的答案。同样动态范围与浅绑定。 (实际上,如果您使用Perl,您可以同时测试两种方式,因为它同时支持两者;只需使用我的作为词法范围,然后执行查找和替换为 local 用于动态范围,但即使您使用JavaScript作为词法作用域,也可以使用Bash作为动态范围,应该很快测试两者)。



具有深度绑定的动态范围更加棘手,因为很少广泛部署的语言支持它。如果使用Perl,您可以通过使用从变量名映射到标量参考的散列(关联数组)手动实现,并将这个散列从函数传递给函数。伪代码声明一个局部变量的地方,你将现有的标量引用保存在一个Perl词汇变量中,然后把新的映射放在哈希中;并且在函数结束时,还原原始的标量引用。为了支持绑定,您创建一个创建哈希的副本的包装函数,并将 传递到其包装函数。这是一个在Perl中使用这种方法的动态范围,深度约束的程序实现:

 #!/ usr / bin / perl -w 

使用警告;
使用strict;

#创建一个新的标量,将其初始化为指定的值
#并返回一个引用:
sub new_scalar($)
{return \ (转移);

#将指定的过程绑定到指定的环境中:
sub bind_proc(\%$)
{
my $ V = {%{+ shift} };
my $ f = shift;
return sub {$ f->($ V,@_); };
}

我的$ V = {};

$ V-> {u} = new_scalar 42; #int u:= 42
$ V-> {v} = new_scalar 69; #int v:= 69
$ V-> {w} = new_scalar 17; #int w:= 17

sub add(\%$)
{
我的$ V = shift;
my $ z = $ V-> {z}; #save existing z
$ V-> {z} = new_scalar shift; #create&初始化新的z
$ {$ V-> {u}} = $ {$ V-> {v}} + $ {$ V-> {u}} + $ {$ V-> {Z}};
$ V-> {z} = $ z; #restore old z
}

子栏(\%$)
{
我的$ V = shift;
我的$ fun = shift;
我的$ u = $ V-> {u}; #save existing u
$ V-> {u} = new_scalar $ {$ V-> {w}}; #create&初始化新的u
$ fun->($ {$ V-> {v}});
$ V-> {u} = $ u; #restore old u
}

sub foo(\%$$)
{
my $ V = shift;
my $ x = $ V-> {x}; #save existing x
$ V-> {x} = new_scalar shift; #create&初始化新的x
我的$ w = $ V-> {w}; #save existing w
$ V-> {w} = new_scalar shift; #create&初始化新的w
我的$ v = $ V-> {v}; #save existing v
$ V-> {v} = new_scalar $ {$ V-> {x}}; #create&初始化新的v
bar%$ V,bind_proc%$ V,\& add;
$ V-> {v} = $ v; #restore old v
$ V-> {w} = $ w; #restore old w
$ V-> {x} = $ x; #restore old x
}

foo%$ V,$ {$ V-> {u}},13;
print$ {$ V-> {u}} \\\
;

__END__

确实打印 126 。这显然是凌乱和容易出错的,但它也真的有助于您了解发生了什么,所以为了教育目的,我认为这是值得的!


I'm studying dynamic/static scope with deep/shallow binding and running code manually to see how these different scopes/bindings actually work. I read the theory and googled some example exercises and the ones I found are very simple (like this one which was very helpful with dynamic scoping) But I'm having trouble understanding how static scope works.

Here I post an exercise I did to check if I got the right solution:

considering the following program written in pseudocode:

int u = 42; 
int v = 69;
int w = 17;
proc add( z:int )
  u := v + u + z
proc bar( fun:proc )
  int u := w;
  fun(v)
proc foo( x:int, w:int )
  int v := x;
  bar(add)
main
  foo(u,13)
  print(u)
end;

What is printed to screen

a) using static scope? answer=180

b) using dynamic scope and deep binding? answer=69 (sum for u = 126 but it's foo's local v, right?)

c) using dynamic scope and shallow binding? answer=69 (sum for u = 101 but it's foo's local v, right?)

PS: I'm trying to practice doing some exercises like this if you know where I can find these types of problems (preferable with solutions) please give the link, thanks!

解决方案

Your answer for lexical (static) scope is correct. Your answers for dynamic scope are wrong, but if I'm reading your explanations right, it's because you got confused between u and v, rather than because of any real misunderstanding about how deep and shallow binding work. (I'm assuming that your u/v confusion was just accidental, and not due to a strange confusion about values vs. references in the call to foo.)

a) using static scope? answer=180

Correct.

b) using dynamic scope and deep binding? answer=69 (sum for u = 126 but it's foo's local v, right?)

Your parenthetical explanation is right, but your answer is wrong: u is indeed set to 126, and foo indeed localizes v, but since main prints u, not v, the answer is 126.

c) using dynamic scope and shallow binding? answer=69 (sum for u = 101 but it's foo's local v, right?)

The sum for u is actually 97 (42+13+42), but since bar localizes u, the answer is 42. (Your parenthetical explanation is wrong for this one — you seem to have used the global variable w, which is 17, in interpreting the statement int u := w in the definition of bar; but that statement actually refers to foo's local variable w, its second parameter, which is 13. But that doesn't actually affect the answer. Your answer is wrong for this one only because main prints u, not v.)


For lexical scope, it's pretty easy to check your answers by translating the pseudo-code into a language with lexical scope. Likewise dynamic scope with shallow binding. (In fact, if you use Perl, you can test both ways almost at once, since it supports both; just use my for lexical scope, then do a find-and-replace to change it to local for dynamic scope. But even if you use, say, JavaScript for lexical scope and Bash for dynamic scope, it should be quick to test both.)

Dynamic scope with deep binding is much trickier, since few widely-deployed languages support it. If you use Perl, you can implement it manually by using a hash (an associative array) that maps from variable-names to scalar-refs, and passing this hash from function to function. Everywhere that the pseudocode declares a local variable, you save the existing scalar-reference in a Perl lexical variable, then put the new mapping in the hash; and at the end of the function, you restore the original scalar-reference. To support the binding, you create a wrapper function that creates a copy of the hash, and passes that to its wrapped function. Here is a dynamically-scoped, deeply-binding implementation of your program in Perl, using that approach:

#!/usr/bin/perl -w

use warnings;
use strict;

# Create a new scalar, initialize it to the specified value,
# and return a reference to it:
sub new_scalar($)
  { return \(shift); }

# Bind the specified procedure to the specified environment:
sub bind_proc(\%$)
{
  my $V = { %{+shift} };
  my $f = shift;
  return sub { $f->($V, @_); };
}

my $V = {};

$V->{u} = new_scalar 42; # int u := 42
$V->{v} = new_scalar 69; # int v := 69
$V->{w} = new_scalar 17; # int w := 17

sub add(\%$)
{
  my $V = shift;
  my $z = $V->{z};                     # save existing z
  $V->{z} = new_scalar shift;          # create & initialize new z
  ${$V->{u}} = ${$V->{v}} + ${$V->{u}} + ${$V->{z}};
  $V->{z} = $z;                        # restore old z
}

sub bar(\%$)
{
  my $V = shift;
  my $fun = shift;
  my $u = $V->{u};                     # save existing u
  $V->{u} = new_scalar ${$V->{w}};     # create & initialize new u
  $fun->(${$V->{v}});
  $V->{u} = $u;                        # restore old u
}

sub foo(\%$$)
{
  my $V = shift;
  my $x = $V->{x};                     # save existing x
  $V->{x} = new_scalar shift;          # create & initialize new x
  my $w = $V->{w};                     # save existing w
  $V->{w} = new_scalar shift;          # create & initialize new w
  my $v = $V->{v};                     # save existing v
  $V->{v} = new_scalar ${$V->{x}};     # create & initialize new v
  bar %$V, bind_proc %$V, \&add;
  $V->{v} = $v;                        # restore old v
  $V->{w} = $w;                        # restore old w
  $V->{x} = $x;                        # restore old x
}

foo %$V, ${$V->{u}}, 13;
print "${$V->{u}}\n";

__END__

and indeed it prints 126. It's obviously messy and error-prone, but it also really helps you understand what's going on, so for educational purposes I think it's worth it!

这篇关于动态/静态范围与深/浅绑定(练习)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆