1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Perl 6Advent Calendar 2017

Day 3

rakudo-and-nqp-internals-courseに挑戦した話 その1

Last updated at Posted at 2017-12-02

こんにちは、3日目の投稿になります。

Introduction

みなさんはrakudo-and-nqp-internals-courseを知っていますか?
rakudo-and-nqp-internalsはMoarVMの開発者であるJonathan Worthington氏の作ったnqpとrakudoの内部構造に関するチュートリアルです。

スライドだけじゃなくて、エクササイズ問題も用意されています。
http://edumentab.github.io/rakudo-and-nqp-internals-course/

というわけで、詳しい話はスライドを見てもらうとして、今回のアドベントカレンダーでは私がエクササイズ問題に挑戦していきたいと思います。

3日目はExercise 1に挑戦します。

Exercise 1

1.1 Hello, World

  • 初めの儀式、Hello, worldをしてみましょうという問題です。
!# nqp

say('Hello, world');

1.2 Variables

  • スカラ、配列、ハッシュに対して値を代入していきましょうという問題です
  • 代入(=)じゃなくて束縛(:=)つかっていくのがポイントです。
!# nqp

my $a := 10;
say($a);

my @b;

@b[0] := 10;

my @c;

@c := [1,2,3];

say(@c[0]);
say(@c[1]);
say(@c[2]);

my $scalar;

$scalar := [1,2,3];

my %h;

%h<key> := 10;
%h{'key'} := 10;

1.3 Loops

  • 配列、ハッシュに対してループ処理を書いてみましょうという問題です
  • 配列のループのところで一度に2つの値を見るのはこんな感じの解き方であってるのかなあというのだけ気になりました (#1)
!# nqp

my @a := [1,2,3];

for @a {
  say($_);
}

for @a -> $val {
  say($val);
}

my @b;
@b[0] := [1,2];
@b[1] := [2,3];

for @b { # (#1)
  say($_[0]);
  say($_[1]);
}

my %h<key> := 10;

for %h {
  say($_.key);
  say($_.value);
}

1.4 Subroutines

  • 階乗を表現する関数を書いてみましょうという問題です。
  • 特にnqp独特の部分はなさそうです。
!# nqp                                                                                                                                                      
                                                                                                                                                            
sub fac($a) {                                                                                                                                               
  $a == 0 ?? 1 !! $a * fac($a - 1)                                                                                                                          
}                                                                                                                                                           
                                                                                                                                                            
say(fac(10));  

1.5 Classes

  • 下記のような複数の問題になっています

    • BarTabクラスをつくって、newメソッドを書いてみる
    • $!num-tables, @!itemsといったアトリビュートを書いてみる
    • $!num-tablesのゲッターのtable()メソッドを書いてみる
    • $name$priceを受け取って@!itemsの中身を更新するadd_orderを書いてみる
    • @!itemsの中身を文字列で提示するrender_tab()を書いてみる
  • nqp::create(), nqp::list(), nqp::push()が見慣れないかもしれません

  • 問題文にBUILDを使いなさいとは書いてなかったかもしれませんが、オブジェクトをnqp::createで作るのはnewに任せて、いろいろな初期化作業はBUILDにやらせる感じにしてみました。

!# nqp                                                                                                                                                      
                                                                                                                                                            
class BarTab {                                                                                                                                              
  has int $!num-tables;                                                                                                                                     
  has @!items;                                                                                                                                              
                                                                                                                                                            
  method new(:$table!) {                                                                                                                                    
    my $obj := nqp::create(self);                                                                                                                           
    $obj.BUILD(:table($table));                                                                                                                             
    $obj                                                                                                                                                    
  }                                                                                                                                                         
  method BUILD(:$table!) {                                                                                                                                  
    $!num-tables := $table;                                                                                                                                 
    @!items := nqp::list();                                                                                                                                 
  }                                                                                                                                                         
  method table() {                                                                                                                                          
    $!num-tables                                                                                                                                            
  }                                                                                                                                                         
  method add_order(str $name, int $price) {                                                                                                                 
    my %h;                                                                                                                                                  
    %h<name> := $name;                                                                                                                                      
    %h<price> := $price;                                                                                                                                    
    nqp::push(@!items, %h);                                                                                                                                 
  }                                                                                                                                                         
  method render_tab() {                                                                                                                                     
    my $total := 0;                                                                                                                                         
    for @!items {                                                                                                                                           
       say($_<name>);                                                                                                                                       
       say($_<price>);                                                                                                                                      
       $total := $total + $_<price>;                                                                                                                        
    }                                                                                                                                                       
    say($total);                                                                                                                                            
  }                                                                                                                                                         
}                                                                                                                                                           
                                                                                                                                                            
my $bar-tab := BarTab.new(table => 42);                                                                                                                     
say($bar-tab.table);                                                                                                                                        
$bar-tab.add_order("name", 1000);                                                                                                                           
$bar-tab.render_tab();                                                                                                                                      

1.6 Multi-methods

  • add_orderをmulti-methodに変更しましょうという問題です。
  • intstrのような型を引数にしていするとうまく動かない(スライドにも書いてある)ので注意が必要です。
!# nqp                                                                                                                                                      
                                                                                                                                                            
class BarTab {                                                                                                                                              
  has int $!num-tables;                                                                                                                                     
  has @!items;                                                                                                                                              
                                                                                                                                                            
  method new(:$table!) {                                                                                                                                    
    my $obj := nqp::create(self);                                                                                                                           
    $obj.BUILD(:table($table));                                                                                                                             
    $obj                                                                                                                                                    
  }                                                                                                                                                         
  method BUILD(:$table!) {                                                                                                                                  
    $!num-tables := $table;                                                                                                                                 
    @!items := nqp::list();                                                                                                                                 
  }                                                                                                                                                         
  method table() {                                                                                                                                          
    $!num-tables                                                                                                                                            
  }                                                                                                                                                         
                                                                                                                
  proto method add_order($name, $price, $quantity?) { * }                                                                                                   
  multi method add_order($name, $price) {                                                                                                                   
    my %h;                                                                                                                                                  
    %h<name> := $name;                                                                                                                                      
    %h<price> := $price;                                                                                                                                    
    nqp::push(@!items, %h);                                                                                                                                 
  }                                                                                                                                                         
  multi method add_order($name, $price, $quantity) {                                                                                                        
    my $i := 0;                                                                                                                                             
    while $i < $quantity {                                                                                                                                  
      my %h;                                                                                                                                                
      %h<name> := $name;                                                                                                                                    
      %h<price> := $price;                                                                                                                                  
      nqp::push(@!items, %h);                                                                                                                               
      $i := $i + 1;                                                                                                                                         
    }                                                                                                                                                       
  }                                                                                                                                                         
  method render_tab() {                                                                                                                                     
    my $total := 0;                                                                                                                                         
    for @!items {                                                                                                                                           
       say($_<name>);                                                                                                                                       
       say($_<price>);                                                                                                                                      
       $total := $total + $_<price>;                                                                                                                        
    }                                                                                                                                                       
    say($total);                                                                                                                                            
  }                                                                                                                                                         
}                                                                                                                                                           
                                                                                                                                                            
my $bar-tab := BarTab.new(table => 42);                                                                                                                     
say($bar-tab.table);                                                                                                                                        
$bar-tab.add_order("name", 1000);                                                                                                                           
$bar-tab.render_tab();                                                                                                                                      

1.7

  • 解いてないです:)

以上、3日目の投稿でした。

ライセンス

rakudo-and-nqp-internals-course is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?