2017-11-23 23 views
1

捕獲変数に依存する関数は、閉鎖型の安定

function function_maker(N) 
    if N == 1 
     x = 1.0 
    else 
     x = 1 
    end 
    f(y) = x+y 
end 

のために、私はタイプ-安定しないと、この出力をしたいが、私はそれが型安定であるfを生成したい作りますすなわちNの値によって決定されるxのタイプを使用して、Nに依存する関数を生成する。基本的には、これから出てくる機能を演奏したいと思っていますが、function_maker自体は演奏する必要はありません。なぜなら、それはグローバルな範囲または機能の障壁の上でしか使われないからです。

f = function_maker(1) 
@code_warntype f(1) 

Variables: 
    #self#::#f#9 
    y::Int64 

Body: 
    begin 
     return ((Core.getfield)((Core.getfield)(#self#::#f#9, :x)::ANY, :contents)::ANY + y::Int64)::ANY 
    end::ANY 

これはデフォルトでは発生しません。私はf(y) = x::typeof(x)+yを試しましたが、それもうまくいきませんでした。これを行う簡単な方法はありますか?

答えて

2

あります:

julia> function function_maker2(N) 
      if N == 1 
       let x = 1.0 
        return f(y) = x + y 
       end 
      else 
       let x = 1 
        return f(y) = x + y 
       end 
      end 
     end 
function_maker2 (generic function with 1 method) 

julia> f2 = function_maker2(1) 
(::f) (generic function with 1 method) 

julia> @code_warntype f2(1) 
Variables: 
    #self#::#f#5{Float64} 
    y::Int64 

Body: 
    begin 
     return (Base.add_float)((Core.getfield)(#self#::#f#5{Float64}, :x)::Float64, (Base.sitofp)(Float64, y::Int64)::Float64)::Float64 
    end::Float64 

このバージョンはletブロック内の各支店でxを分離。それ以外の場合、コンパイラは混乱するようです。

+1

面白いです!変数(xとxx)を変更しても助けにならない:function function_maker3(N)N == 1 && begin x = 1. return y - > x + y end || begin xx = 1; return y - > xx + y end end'である。しかし、最初のもの(!) 'begin'だけを' let'と置き換えると動作します。そして、2番目のものだけを置き換えることはできません。 – Liso

+1

本当にクールな答え!これは間違いなく私が心に留めなければならないトリックです。 –

+0

@Lisoあなたが言うことは面白いです。 2つの変数名関数が型安定した 'f'を返すようにするには、条件付き前に' local x :: Float64、xx :: Int64'を追加する必要がありました。おそらくコンパイラは型の不確実性を持っていません未処理の条件付きパス内のローカル変数第1と第2の間の 'let'の非対称性については、' function_maker(1) 'と' function_maker(2) 'の両方で' f'の安定性をテストしましたか?おそらく 'let'ブランチは安定していて、もう一方のブランチは安定していません。 –