JuliaTokyo / julia-wakalang

Juliaのわからないことへの質問を雑にする場所
MIT License
25 stars 3 forks source link

"Endogenous" parameterization #18

Closed oyamad closed 8 years ago

oyamad commented 8 years ago

こんにちは. 文脈を説明することなしに質問するのは難しいのですが,質問させていただきます.

自然数 N をパラメタに持つタイプを引数とし,N-1 をパラメタに持つタイプを返り値にするような関数を,@code_warntype で問題がないように書くにはどうするものなのでしょうか.

たとえばこんな関数を書きたいとします. (別に Tuple である必要はなく,N 次元 Array の input,N-1 次元 Array の output でもかまいません.)

function func{N,T<:Real}(t::NTuple{N,T})
    M = N - 1
    out = ntuple(i -> t[i+1], M)::NTuple{M,T}
    return out
end
julia> func((1, 2, 3))
(2,3)

(Tuple{Int64,Int64,Int64} を入れると Tuple{Int64,Int64} が返る.)

これだと @code_warntype func((1, 2, 3)) で太文字 (REPL だと赤文字) がたくさん出ます (とくに out に関して).

Variables:
  t::Tuple{Int64,Int64,Int64}
  M::Int64
  out::NTUPLE{N,INT64}

Body:
  begin  # In[1], line 2:
      M = (Base.box)(Int64,(Base.sub_int)(3,1)) # In[1], line 3:
      out = (top(typeassert))((Main.ntuple)(AST(:($(Expr(:lambda, Any[:(i::Any::ANY)], Any[Any[Any[:i,Any,0]],Any[Any[:t,Tuple{Int64,Int64,Int64},1]],0,Any[:N,:T]], :(begin  # In[1], line 3:
        return (Main.getindex)(t,i + 1::ANY)::ANY
    end::ANY))))),M::Int64)::TUPLE,(top(apply_type))(Main.NTuple,M::Int64,T)::TYPE{_<:NTUPLE{N,INT64}})::NTUPLE{N,INT64} # In[1], line 4:
      return out::NTUPLE{N,INT64}
  end::NTUPLE{N,INT64}

::NTuple{M,T} (where M = N-1) という宣言が有効でないようです.

@generated というのを使うと (anonymous function 以外で) 問題は出なくなります.

@generated function func_g{N,T<:Real}(t::NTuple{N,T})
    return quote
        $(M = N - 1)
        out = ntuple(i -> t[i+1], $M)::NTuple{$M,T}
        return out
    end
end

@code_warntype func_g((1, 2, 3)):

Variables:
  t::Tuple{Int64,Int64,Int64}
  out::Tuple{Int64,Int64}

Body:
  begin  # In[4], line 2: # In[4], line 3: # In[4], line 4:
      out = (top(typeassert))((Main.ntuple)(AST(:($(Expr(:lambda, Any[:(i::Any::ANY)], Any[Any[Any[:i,Any,0]],Any[Any[:t,Tuple{Int64,Int64,Int64},1]],0,Any[:N,:T]], :(begin  # In[4], line 4:
        return (Main.getindex)(t,i + 1::ANY)::ANY
    end::ANY))))),2)::TUPLE,Tuple{Int64,Int64})::Tuple{Int64,Int64} # In[4], line 5:
      return out::Tuple{Int64,Int64}
  end::Tuple{Int64,Int64}

これで「解決」なのですが,私自身 @generated をまったく理解していないので,できれば使いたくない.こういう難しいのを使わない "普通の" 書き方でうまい方法はないものでしょうか.

oyamad commented 8 years ago

JuliaTokyo 6 で @bicycle1885 さんにいろいろ教わったのでここに記録しておく.

1. 上の例じたい (Tuple t から t[2:end] を返す) は Base.tail でできる.

julia> Base.tail((1, 2, 3))
(2,3)

2. Tuple から任意の i 番目の要素を落とす方法はここに書いてある.

3. Tuple t から t[1:end-1] を返すのは,0.5に Base.front というのが入っていました.

julia> Base.front((1, 2, 3))
(1,2)