푸시 후 영향을받는 스칼라 값… (Raku)


12

푸시 Scalar된 컨테이너가 보유한 값 이 푸시 후 영향을받는 시기와 이유를 이해하기가 어렵습니다 . 두 가지 양식화 된 예제에서보다 복잡한 컨텍스트에서 발생한 문제를 설명하려고합니다.

* 예 1 * 첫 번째 예에서 스칼라 $i@ba의 일부로 배열에 푸시 List됩니다. 푸시 후 스칼라가 보유한 값은 $i++명령어를 사용하여 for 루프의 이후 반복에서 명시 적으로 업데이트됩니다 . 이러한 업데이트는 배열의 값에 영향을 미칩니다 @b. for 루프의 끝에서는 @b[0;0]같고 3더 이상 같지 않습니다 2.

my @b;
my $i=0;
for 1..3 -> $x {
  $i++;
  say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
  if $x == 2 {
     @b.push(($i,1));
     say 'Pushed $i   : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;
  }
}
say "Post for-loop";
say "Array       : ", @b;
say 'Pushed $i   : ', @b[0;0].VAR.WHICH, " ", @b[0;0].VAR.WHERE;

출력 예 1 :

Loose var $i: Scalar|94884317665520 139900170768608
Loose var $i: Scalar|94884317665520 139900170768648
Pushed $i   : Scalar|94884317665520 139900170768648
Loose var $i: Scalar|94884317665520 139900170768688
Post for-loop
Array       : [(3 1)]
Pushed $i   : Scalar|94884317665520 139900170768688

* 예 2 * 두 번째 예에서 스칼라 $i는 루프 변수입니다. $i푸시 된 후에 업데이트 되지만 (현재 명시 적으로가 아니라 암시 적으로) 푸시 후에 $i배열 의 값이 변경 @c되지 않습니다 . 즉, for 루프 후에도 여전히 2아닙니다 3.

my @c;
for 1..3 -> $i {
  say 'Loose var $i: ', $i.VAR.WHICH, " ", $i.VAR.WHERE;
  if $i == 2 {
     @c.push(($i,1));
     say 'Pushed $i   : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;
  }
}
say "Post for-loop";
say "Array       : ", @c;
say 'Pushed $i   : ', @c[0;0].VAR.WHICH, " ", @c[0;0].VAR.WHERE;;

출력 예 2 :

Loose var $i: Scalar|94289037186864 139683885277408
Loose var $i: Scalar|94289037186864 139683885277448
Pushed $i   : Scalar|94289037186864 139683885277448
Loose var $i: Scalar|94289037186864 139683885277488
Post for-loop
Array       : [(2 1)]
Pushed $i   : Scalar|94289037186864 139683885277448

질문 :$i@b있는 동안, 푸시 후 업데이트 실시 예 1에서 $i@c예 2에서이 아닌가요?

edit : @timotimo의 의견 .WHERE에 따라 예제에 출력을 포함 시켰습니다 . 이것은 (WHICH / 논리) 스칼라 ID가 $i동일하게 유지되고 메모리 주소가 다양한 루프 반복을 통해 변경됨을 나타냅니다. 그러나 예제 2에서 푸시 된 스칼라가 왜 이전 주소 ( "448)와 결합하여 동일한 WHICH ID에 연결되어 있는지에 대해서는 설명하지 않습니다.


2
왜 WHICH가 동일하게 유지되는지에 대한 답을 줄 수 있습니다. 구현을 살펴보십시오 : github.com/rakudo/rakudo/blob/master/src/core.c/Scalar.pm6#L8- 사용되는 설명자에만 의존합니다. 변수 및 형식 제약 조건 당신이 사용하는 경우 .WHERE대신 .WHICH당신 스칼라 다른 객체가 루프 주위 때마다 실제로 볼 수 있습니다. 이는 뾰족한 블록이 "호출"되고 각 호출에서 서명이 "바운드"되기 때문에 발생합니다.
timotimo

@raiph 루프 동안 예제 1은 예제 2와 동일한 패턴을 보여줍니다. 그러나 그 자체로는 왜 예제 2가 예제 1과 다른 결말을 가져 오는지 설명하지 않습니다.
ozzy

답변:


5

스칼라 값은 컨테이너 일뿐입니다. 그것들을 기본 값이 아닌 일종의 스마트 포인터로 생각할 수 있습니다.

과제를하면

$foo = "something"; #or
$bar++;

스칼라 값을 변경하면 컨테이너가 동일하게 유지됩니다.

치다

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i++; 
  @b.push(($i<>,1)); # decontainerize $i and use the bare value
} 
say @b;

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i := $i + 1;  # replaces the container with value / change value
  @b.push(($i,1)); 
} 
say @b;

둘 다 예상대로 작동합니다. 그러나 두 경우 모두 컨테이너가 없기 때문에 목록의 내용은 더 이상 변경할 수 없습니다.

@b[4;0] = 99; 

그러므로 죽을 것이다. 그렇다면 루프 변수를 사용하십시오.

아니.

for 1..5 -> $x { 
  @b.push(($x,1)); # 
} 
@b[4;0] = 99; #dies

우리가 변경 가능한 것들의 목록을 반복하더라도.

my $one = 1;
my $two = 2;
my $three = 3;
my $four = 4;
my $five = 5;

for ($one, $two, $three, $four, $five) -> $x { 
  @b.push(($x,1)); 
} 
@b[4;0] = 99; #dies

따라서 여기서 발생하는 앨리어싱이 없으며 대신 루프 변수는 항상 동일한 컨테이너이며 다른 컨테이너에서 오는 값이 할당됩니다.

그래도 가능합니다.

for ($one, $two, $three, $four, $five) <-> $x { 
  @b.push(($x,1)); 
} 
@b[4;0] = 99; # works

for ($one, $two, $three, $four, $five) -> $x is rw { 
  @b.push(($x,1)); 
} 
@b[4;0] = 99; # works too

"사물"을 변경 가능하게하는 방법은 중간 변수를 사용하는 것입니다.

for 1..5 -> $x { 
  my $j = $x;
  @b.push(($j,1)); # a new container 
} 
@b[4;0] = 99;

잘 작동합니다. 또는 원래 상황에서 더 짧거나 더

my @b; 
my $i=0; 
for 1..5 -> $x { 
  $i++; 
  @b.push((my $ = $i, 1)); # a new anonymous container
} 
@b[4;0] = 99;
say @b; # [(1 1) (2 1) (3 1) (4 1) (99 1)]

또한보십시오:

https://perl6advent.wordpress.com/2017/12/02/#theoneandonly https://docs.perl6.org/language/containers


1
대신에 ($x,1), 당신은 또한 할 수 [$x,1]있는 (위해 또한 새로운 컨테이너를 만들 1BTW)
엘리자베스 Mattijsen

@ElizabethMattijsen 그러나 "리프팅"을하는 것은 배열입니까?
Holli

"리프팅 (lifting)"이 무슨 뜻인지 확실하지 않지만, 생성시 값을 컨테이너화하면 예입니다.
엘리자베스 마티 지센 19

@Holli 답장을 보내 주셔서 감사합니다. 그래도 질문이 해결되는지 확실하지 않습니다. 귀하의 답변은 컨테이너의 가변성에 중점을 둡니다. 내가 이해하지 못하는 것은 첫 번째 예제에서 푸시 된 컨테이너 $ i 또는 그 이상 : 그 값-푸시 후 업데이트되는 이유입니다. 두 번째 예제에서는 푸시 된 컨테이너의 값이 현재 값과 정적으로 연결되어 있습니다. 푸시의. 첫 번째 예제는 나에게 의미가 있습니다 (컨테이너는 Int객체 Int에 대한 포인터입니다 -> for 루프로 대체됩니다-> 컨테이너 포인트는 new Int).하지만 두 번째 예제는 그렇지 않습니다.
ozzy

@Holli 질문을 명확하게하겠습니다.
ozzy

3

잠시 동안 위의 질문에 대해 생각하고 생각한 후에, 나는 대답을 베풀 것입니다 ... 그것은 순수한 추측입니다. 그렇다면 말도 안된다고 말하고, 알고 있다면, 왜...

첫 번째 예에서는 $ifor 루프의 어휘 범위 외부에서 정의됩니다. 결과적으로 $i루프 및 반복과 독립적으로 존재합니다. $i루프 내부에서 참조 될 때 $i영향을받을 수있는 것은 하나뿐입니다 . 이것은로 $i푸시되어 @b나중에 루프에서 내용이 수정됩니다.

두 번째 예에서는 $ifor 루프의 어휘 범위 내에 정의되어 있습니다. @timotimo가 지적했듯이 뾰족한 블록은 서브 루틴처럼 각 반복마다 호출됩니다. $i따라서 각 반복에 대해 새롭게 선언되고 해당 블록으로 범위가 지정됩니다. $i루프 내에서 참조 되면 블록 반복 특정 참조가 발생하며 $i, 이는 일반적으로 각 루프 반복이 종료되면 존재하지 않습니다. 그러나 어떤 시점에서 $i로 푸시 @c되었으므로 반복 종료 후 가비지 콜렉터 가 블록 반복 특정 $i보유 값에 대한 참조를 2삭제할 수 없습니다. 그것은 계속 존재하지만 $i나중에 반복 되는 것과는 여전히 다릅니다 .


감사합니다. 내가 할게. 아마도 나보다 통찰력이있는 사람이 대답을 올바르게 (재) 구문 할 수있을 것입니다. 나는 (나 자신처럼 추측하기보다는) 아는 사람들에 의해 확인 (또는 개선) 될 때까지 내 자신의 대답을 올바른 것으로 받아들이지 않을 것이다.
ozzy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.