2017-08-11 7 views
0

私は実行しようとしている一連の3つのネストされた関数を持っています。私は最も内側の関数のデフォルトの引数を、最も外側の関数から渡されるリストオブジェクト内の要素として指定したいと思います。これは説明するのが少し難しいので、元のコードと同じ引数とオブジェクトを使用する再現可能な例を作成しました。コードの量を許してくださいが、私はこの例をできるだけオリジナルに近づけたいと思っていました。ネストしたR関数が既存のオブジェクトを引数として認識しないのはなぜですか?

機能CreateBirthDatesが問題の原因です。 4つの引数は、リストオブジェクト内のすべての要素であるsim(たとえば、sim$agents$input)です。私はsimに最初の関数wrapperを呼び出し、次に2番目の関数UpdateAgentStatesを呼び出します。 UpdateAgentStatesの中でsim(例えば、sim$agents$birth_day)内の他のオブジェクトを使用してsim$agents$inputを変更したいと思います。これらの他の引数は常に同じなので、私はそれらを「ハードワイヤリング」したいと思います。しかし、wrapper関数を実行すると、CreateBirthDatessimを認識せず、したがってデフォルトの引数を指定することはできません。

CreateBirthDatesの代替バージョン: CreateBirthDates_with_simを作成しました。これには、引数としてsimが含まれます。この関数をラッパー関数で実行すると機能します!

これは "これは道のりのR作品"のようなものですが、私はその理由を完全には理解していません。私は基本的なプログラミングのスキルを向上させたいので、どんな提案やコメントも高く評価されます。

ジャワ

、非常に多く、以下を参照してくださいコード ありがとう:

# Create some example data and load the package lubridate ----- 
    library(lubridate) 

    t1 <- list("agents"=list("input"=data.frame(id=seq(1:5),class=rep("Male",5),age=rep(6,5))), 
     "pars"=list("global"=list("input_age_period"="years", 
            "birth_day"="01Sep", 
            "sim_start"=as.POSIXct("2000-10-01")))) 

    # Specify the original functions ------- 

    wrapper <- function(sim,use_sim=FALSE){ 

     if(use_sim==FALSE){ 
UpdateAgentStates(agent_states = NULL,sim=sim,init=TRUE) 
     } else { 
UpdateAgentStates_with_sim(agent_states = NULL,sim=sim,init=TRUE) 
     } 
    } 

    UpdateAgentStates <- function(agent_states = NULL, 
    sim = sim, 
    init = FALSE 
    ) { 
     if (init == TRUE) { 
input <- sim$agents$input 
input <- CreateBirthDate(input) 
sim$input <- input 
return(sim) 
     } 
    } 

    UpdateAgentStates_with_sim <- function(agent_states = NULL, 
          sim = sim, 
          init = FALSE 
    ) { 
     if (init == TRUE) { 
input <- sim$agents$input 
input <- CreateBirthDate_with_sim(input, sim=sim) 
sim$input <- input 
return(sim) 
     } 
    } 

    CreateBirthDate <- 
    function(input = sim$agents$input, 
    input_age_period = sim$pars$global$input_age_period, 
    birth_day = sim$pars$global$birth_day, 
    starting_day = sim$pars$global$sim_start 
    ){ 

     # Only proceed if there is no birth_date column 
     if(is.null(input$birth_date)){ 
# Loop through each row in the input 
for(a in 1:nrow(input)){ 
    # Is the age_period a year? 
    if(input_age_period == "year" || input_age_period == "years") { 
    # Determine the first sim_start date after the birth_day 
    one_year <- as.period(1, "year") 
    s0 <- as.Date(starting_day - (one_year*input$age[a])) 
    # Set the format of the birth_day 
    birth_day_format <- guess_formats(birth_day,"dm") 
    birth_day_format <- paste(birth_day_format,"%Y",sep="") 
    # Determine the first birth_day after s0 
    s1 <- as.Date(paste(birth_day,year(s0),sep=""), format=birth_day_format) 
    if(length(s1)>1){ 
     s1 <- s1[-(which(is.na(s1)))] 
    } 
    if(s0 >= s1) { 
     input$birth_date[a] <- as.character(s1) 
    } else { 
     input$birth_date[a] <- as.character(s1-one_year) 
    } 
    } else { 
    # If age period is not a year 
    age_period_unit <- as.period(1, input_age_period) 
    input$birth_date[a] <- as.character(starting_day - 
              (age_period_unit*input$age[a])) 
    } 
} 
     } 
     # Convert birth_date to a POSIXct object 
     # input$birth_date <- as.POSIXct(input$birth_date, tz = 
     # tz(sim$pars$global$sim_start)) 
     return(input) 
    } 

    # Specify the modified functions ------- 

    CreateBirthDate_with_sim <- 
     function(input = sim$agents$input, 
     input_age_period = sim$pars$global$input_age_period, 
     birth_day = sim$pars$global$birth_day, 
     starting_day = sim$pars$global$sim_start, sim=sim 
     ){ 

# Only proceed if there is no birth_date column 
if(is.null(input$birth_date)){ 
    # Loop through each row in the input 
    for(a in 1:nrow(input)){ 
    # Is the age_period a year? 
    if(input_age_period == "year" || input_age_period == "years") { 
     # Determine the first sim_start date after the birth_day 
     one_year <- as.period(1, "year") 
     s0 <- as.Date(starting_day - (one_year*input$age[a])) 
     # Set the format of the birth_day 
     birth_day_format <- guess_formats(birth_day,"dm") 
     birth_day_format <- paste(birth_day_format,"%Y",sep="") 
     # Determine the first birth_day after s0 
     s1 <- as.Date(paste(birth_day,year(s0),sep=""), format=birth_day_format) 
     if(length(s1)>1){ 
     s1 <- s1[-(which(is.na(s1)))] 
     } 
     if(s0 >= s1) { 
     input$birth_date[a] <- as.character(s1) 
     } else { 
     input$birth_date[a] <- as.character(s1-one_year) 
     } 
    } else { 
     # If age period is not a year 
     age_period_unit <- as.period(1, input_age_period) 
     input$birth_date[a] <- as.character(starting_day - 
              (age_period_unit*input$age[a])) 
    } 
    } 
     } 
     # Convert birth_date to a POSIXct object 
     # input$birth_date <- as.POSIXct(input$birth_date, tz = 
     # tz(sim$pars$global$sim_start)) 
     return(input) 
     } 

    # Try running the wrapper function ------------- 

    # Original version, doesn't work 
    wrapper(t1, use_sim = FALSE) 

    # But if I add an argument for sim to CreateBirthDate 
    wrapper(t1, use_sim = TRUE) 
+1

これは、最小限で再現性のある例を並べ替えるにはあまりにも多くのコードと同じように思えます。 'CreateBirthDate'関数のデフォルト値はすべて' sim $ 'を使うようですが' sim'はその関数のパラメータではありません。希望の振る舞いが何であるかは私には不明です。 R関数のパラメータは、それ自身のレキシカルスコープの外の変数を見ることができません。関数が値を使用するようにするには、その値をパラメータとして渡します。 – MrFlick

答えて

0

を別のグローバル関数内でグローバル関数を使用して、別の関数内で関数を定義するには違いがあります。この最初の例でinner_funcのスコープは(ない変数だけをt1)地球環境とSIMが地球環境に存在しないです。

t1 <- 1 

inner_func <- function() { 
    final <- sim*2 
    return(final) 
} 

outer_func <- function(sim = w){ inner_func() } 

outer_func(t1) 

Error in inner_func() : object 'sim' not found 

しかし、我々はouter_funcの内側inner_funcを定義した場合、あなたは意志

t1 <- 1 

outer_func <- function(sim = w){ 
    inner_func <- function() { 
    final <- sim*2 
    return(final) 
    } 
    inner_func() 
} 

outer_func(t1) 
[1] 2 
+0

お返事ありがとうございます!私はなぜ 'CreateBirthDate'が' UpdateAgentStates'の中にネストされ、 'sim'が' UpdateAgentStates'の引数としてインクルードされているのか、なぜ 'sim'が存在しないのか、混乱しているのでしょうか?私はあなたが関数に引数として与えるものは、作業環境の一部となり、後でネストされた関数に利用できると考えました。あなたの助けをもう一度ありがとう! – JBauder

+0

更新された回答を参照してください。 – AidanGawronski

関連する問題