ブロックの中でのpメソッドの使用について

[code]

    p (0..10).map{|n| 1 == 1}
    
[/code]

の結果は  
[true, true, true, true, true, true, true, true, true, true, true]  
ですが、eachの中でのpメソッドの使用した

①

[code]

    (3..8).each{|p|
      p (0..10).map{|n| 1 == 1}
    }
    
[/code]

の結果は  
0..10  
0..10  
0..10  
0..10  
0..10  
0..10  
となってしまいます。  
このことを回避するために、

②

[code]

    (3..8).each{|p|
      p ((0..10).map{|n| 1 == 1})
    }
    
[/code]

としたのですが、どうして上記のようなことが起こるのか教えてください。  
また、修正の仕方は②で良かったのか教えていただければ幸いです。

（追記）  
1.（②以外の修正を行う場合の）要件  
質問の都合上条件の式を 1==1 としていますが、  
本当は 変数pに関する数式が入るので、  
**できれば変数はpのままにしておきたい。**  
2.背景  
プログラミングの話でなく、数学の話になって恐縮ですが、  
p進数（<https://ja.wikipedia.org/wiki/P%E9%80%B2%E6%95%B0>）  
というものがあります。  
pという記号を使うのが慣例のようなものです。  
よって、プログラミングではiでもpでもどちらでもよいのですが、  
数学でpを使用している以上なるべ‌​くpを使いたい。




どうして、についてですが、

[code]

    p (0..10).map{|n| 1 == 1}
    
[/code]

が

[code]

    (p(0..10)).map{|n| 1 == 1}
    
[/code]

と解釈されてしまったためです。通常は以下の様に `map` の処理の結果が `p` メソッドの引数として渡されるのですが、

[code]

    p (0..10).map{|n| 1 == 1 }
    [true, true, true, true, true, true, true, true, true, true, true]
    => [true, true, true, true, true, true, true, true, true, true, true]
    
[/code]

p に何らかの値をバインドすると、

[code]

    p = 1
    => 1
    p (0..10).map{|n| 1 == 1 }
    0..10
    => [true, true, true, true, true, true, true, true, true, true, true]
    
[/code]

となってしまいます。詳しくはソースコードで確認する必要がありますが、眠いのでここまでとします。

なお、どうしても `p` という symbol を同時に使いたいのであれば、以下の様にしても良いかもしれません。

[code]

    (3..8).each{|p|
      p Range.new(0, 10).map{|n| 1 == 1}
    }
    
[/code]

でもまぁ、これなら Manyama さんの `p ((0..10).map{|n| 1 == 1})` の方が良いでしょうね。

**追記**

Ruby のソースコードの parse.y ファイルに [tokenize_ident
関数](https://github.com/ruby/ruby/blob/trunk/parse.y#L7600)
があって、この関数での処理が原因の様です。

[code]

    static void
    tokenize_ident(struct parser_params *parser, const enum lex_state_e last_state)
    {
      ID ident = TOK_INTERN();
    
      set_yylval_name(ident);
      if (!IS_lex_state_for(last_state, EXPR_DOT|EXPR_FNAME) &&
        is_local_id(ident) && lvar_defined(ident)) {
        lex_state = EXPR_END;
      }
    }
    
[/code]

`is_local_id(ident) && lvar_defined(ident))`
となっていて、シンボルがローカル変数として定義されている場合はパースの仕方を変えています。

[code]

    irb> defined? p
    => "method"
    irb> p (1..3).map{|n| n}
    [1, 2, 3]
    => [1, 2, 3]
    
    irb> p = 1
    irb> defined? p
    => "local-variable"
    irb> p (1..3).map{|n| n}
    1..3
    => [1, 2, 3]
    
[/code]

そこで if 文をコメントアウトして再ビルドしてみました。

[code]

    set_yylval_name(ident);
    /*
    if (!IS_lex_state_for(last_state, EXPR_DOT|EXPR_FNAME) &&
      is_local_id(ident) && lvar_defined(ident)) {
      lex_state = EXPR_END;
    }
    */
    
[/code]

実行結果です。

[code]

    irb> (3..8).each{|p|
    irb*   p (0..10).map{|n| 1 == 1}
    irb> }
    [true, true, true, true, true, true, true, true, true, true, true]
    [true, true, true, true, true, true, true, true, true, true, true]
                    :
    
[/code]

期待通りの結果になりましたが、なぜにあの様な処理になっているのかについては不明です。VCS のログを漁れば何か判るかもしれませんが…。




どうして、についてですが、

[code]

    p (0..10).map{|n| 1 == 1}
    
[/code]

が

[code]

    (p(0..10)).map{|n| 1 == 1}
    
[/code]

と解釈されてしまったためです。通常は以下の様に `map` の処理の結果が `p` メソッドの引数として渡されるのですが、

[code]

    p (0..10).map{|n| 1 == 1 }
    [true, true, true, true, true, true, true, true, true, true, true]
    => [true, true, true, true, true, true, true, true, true, true, true]
    
[/code]

p に何らかの値をバインドすると、

[code]

    p = 1
    => 1
    p (0..10).map{|n| 1 == 1 }
    0..10
    => [true, true, true, true, true, true, true, true, true, true, true]
    
[/code]

となってしまいます。詳しくはソースコードで確認する必要がありますが、眠いのでここまでとします。

なお、どうしても `p` という symbol を同時に使いたいのであれば、以下の様にしても良いかもしれません。

[code]

    (3..8).each{|p|
      p Range.new(0, 10).map{|n| 1 == 1}
    }
    
[/code]

でもまぁ、これなら Manyama さんの `p ((0..10).map{|n| 1 == 1})` の方が良いでしょうね。

**追記**

Ruby のソースコードの parse.y ファイルに [tokenize_ident
関数](https://github.com/ruby/ruby/blob/trunk/parse.y#L7600)
があって、この関数での処理が原因の様です。

[code]

    static void
    tokenize_ident(struct parser_params *parser, const enum lex_state_e last_state)
    {
      ID ident = TOK_INTERN();
    
      set_yylval_name(ident);
      if (!IS_lex_state_for(last_state, EXPR_DOT|EXPR_FNAME) &&
        is_local_id(ident) && lvar_defined(ident)) {
        lex_state = EXPR_END;
      }
    }
    
[/code]

`is_local_id(ident) && lvar_defined(ident))`
となっていて、シンボルがローカル変数として定義されている場合はパースの仕方を変えています。

[code]

    irb> defined? p
    => "method"
    irb> p (1..3).map{|n| n}
    [1, 2, 3]
    => [1, 2, 3]
    
    irb> p = 1
    irb> defined? p
    => "local-variable"
    irb> p (1..3).map{|n| n}
    1..3
    => [1, 2, 3]
    
[/code]

そこで if 文をコメントアウトして再ビルドしてみました。

[code]

    set_yylval_name(ident);
    /*
    if (!IS_lex_state_for(last_state, EXPR_DOT|EXPR_FNAME) &&
      is_local_id(ident) && lvar_defined(ident)) {
      lex_state = EXPR_END;
    }
    */
    
[/code]

実行結果です。

[code]

    irb> (3..8).each{|p|
    irb*   p (0..10).map{|n| 1 == 1}
    irb> }
    [true, true, true, true, true, true, true, true, true, true, true]
    [true, true, true, true, true, true, true, true, true, true, true]
                    :
    
[/code]

期待通りの結果になりましたが、なぜにあの様な処理になっているのかについては不明です。VCS のログを漁れば何か判るかもしれませんが…。

