0Pricing
R Academy · レッスン

withCallingHandlers()と再起動

withCallingHandlers()を使って、非局所的なコンディション処理を行います。

「withCallingHandlers()と再起動」はCoddyKit上の無料R Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはR Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 R Academyコースには全4レッスンが含まれています。

tryCatchとwithCallingHandlersの比較

主な違いは、tryCatch()が非局所的な脱出を行う点です。条件が捕捉されると、制御は式の外へ移り、式には戻りません。一方、withCallingHandlers()はコールスタックを維持し、処理後に実行を再開できます。

# tryCatch: execution does NOT continue after warning
tryCatch({
  warning('first')
  cat('This line is never reached\n')
}, warning = function(w) cat('tryCatch caught:', w$message, '\n'))

withCallingHandlersは実行を継続する

withCallingHandlers()では、ハンドラーが実行された後も、条件が通知された位置から実行が続きます(ただし、ハンドラー自身がエラーを発生させたり、restartを呼び出したりした場合を除きます)。コールスタックは巻き戻されません。

withCallingHandlers({
  warning('first warning')
  cat('Execution continues here\n')
  warning('second warning')
  cat('And here too\n')
}, warning = function(w) {
  cat('Handler saw:', w$message, '\n')
  invokeRestart('muffleWarning')
})

muffleWarning restart

警告ハンドラー内でinvokeRestart('muffleWarning')を呼び出すと、Rのデフォルトハンドラーによる警告の表示を抑制できます。これを行わない場合、ハンドラーの実行後も、Rのデフォルトの仕組みによって警告が表示されます。

# Without muffleWarning: warning still shows after handler
withCallingHandlers({
  warning('test')
}, warning = function(w) {
  cat('Handler ran\n')
  # no muffleWarning: default handler still fires
})

muffleMessage restart

同様に、メッセージハンドラー内でinvokeRestart('muffleMessage')を呼び出すと、カスタムハンドラーで処理した後のメッセージを非表示にできます。suppressMessages()はこの仕組みを利用しています。

withCallingHandlers({
  message('Progress: 50%')
  message('Progress: 100%')
}, message = function(m) {
  cat('[LOG]', trimws(m$message), '\n')
  invokeRestart('muffleMessage')
})

停止せずに警告をログに記録する

withCallingHandlers()の実用的な使い方として、コードの完了を妨げずに警告をログ用のベクトルへ収集する方法があります。tryCatch()は最初の警告で停止しますが、withCallingHandlers()はすべての警告を収集します。

warnings_log <- character(0)
result <- withCallingHandlers({
  x <- log(-1)
  y <- sqrt(-4)
  c(x, y)
}, warning = function(w) {
  warnings_log <<- c(warnings_log, w$message)
  invokeRestart('muffleWarning')
})
cat('Warnings logged:', length(warnings_log), '\n')
cat(warnings_log, sep = '\n')

invokeRestart()の概念

restartは、条件を通知するコードが提供できる、あらかじめ定義された回復戦略です。invokeRestart(name)で、その戦略の1つを選択します。組み込みのrestartには'muffleWarning'と'muffleMessage'があり、withRestarts()でカスタムrestartを定義できます。

# withRestarts() offers named recovery options
divide_safe <- function(x, y) {
  withRestarts(
    {
      if (y == 0) stop('division by zero')
      x / y
    },
    use_zero = function() 0,
    use_na   = function() NA
  )
}
# A handler can pick a restart
withCallingHandlers(
  divide_safe(10, 0),
  error = function(e) invokeRestart('use_zero')
)

withCallingHandlersとtryCatchの組み合わせ

この2つはネストして使用できます。外側でwithCallingHandlers()を使って条件をログに記録したり数えたりし、内側のtryCatch()でフォールバック値を提供します。外側のハンドラーが先に条件を確認します。

n_warnings <- 0L
result <- withCallingHandlers(
  tryCatch(log(-1), warning = function(w) -999),
  warning = function(w) {
    n_warnings <<- n_warnings + 1L
    cat('Logged warning #', n_warnings, '\n')
  }
)
cat('Result:', result, '\n')

カスタム条件クラス

クラスc('myError', 'error', 'condition')を持つリストに対してstructure()を呼び出すと、カスタム条件クラスを作成できます。ハンドラーはクラスに基づいて照合するため、カスタムクラスを使えば、すべてのエラーを捕捉せずに特定のエラー型だけを捕捉できます。

my_error <- function(msg, data = NULL) {
  structure(
    class = c('my_error', 'error', 'condition'),
    list(message = msg, data = data)
  )
}
tryCatch(
  stop(my_error('custom error', data = 42)),
  my_error = function(e) cat('Custom handler, data=', e$data, '\n'),
  error    = function(e) cat('Generic handler\n')
)

withCallingHandlersを使う場面

実行を停止せずに条件を監視またはログに記録したい場合は、withCallingHandlers()を使用します。条件から回復して代替値を返したい場合は、tryCatch()を使用します。両者は異なる問題を解決します。

# withCallingHandlers: observe all, continue
withCallingHandlers(
  for (x in c(4, -1, 9, -4)) cat(suppressWarnings(sqrt(x)), ''),
  warning = function(w) cat('[warn]', '')
)
cat('\n')

条件通知の連鎖

条件が通知されると、Rはハンドラーを探してコールスタックを上へたどります。withCallingHandlers()のハンドラーは動的コンテキスト(コールスタックが維持された状態)で実行されます。tryCatch()のハンドラーは巻き戻し後に実行されるため、元のコンテキストは失われています。

# Demonstrate: withCallingHandlers handler can see full stack
f <- function() {
  withCallingHandlers(
    g(),
    warning = function(w) {
      cat('Caught in f, stack length:', sys.nframe(), '\n')
      invokeRestart('muffleWarning')
    }
  )
}
g <- function() warning('from g')
f()

suppressWarnings()の実装

suppressWarnings(expr)は、本質的にはwithCallingHandlers(expr, warning = function(w) invokeRestart('muffleWarning'))です。これを理解すると、特定の警告型だけを抑制する独自のバリエーションを作成できます。

# Suppress only NaN warnings, not others
suppress_nan_warn <- function(expr) {
  withCallingHandlers(expr, warning = function(w) {
    if (grepl('NaN', conditionMessage(w)))
      invokeRestart('muffleWarning')
  })
}
suppress_nan_warn(log(-1))   # NaN warning suppressed
tryCatch(
  suppress_nan_warn(warning('other issue')),
  warning = function(w) cat('Other warning kept:', w$message, '\n')
)

確認問題

withCallingHandlers()とtryCatch()の主な違いは何ですか?

restart: 重要なポイント

withCallingHandlersとrestartの重要なポイント:

  • withCallingHandlers() = 局所的なハンドラー、コールスタックを維持、実行を継続可能
  • tryCatch() = 非局所的な脱出、スタックを巻き戻し、代替値を返すことが可能
  • invokeRestart('muffleWarning')で警告のデフォルト表示を抑制します
  • invokeRestart('muffleMessage')でメッセージのデフォルト表示を抑制します
  • 停止せずにすべての条件を収集またはログに記録するには、withCallingHandlers()を使用します
  • カスタム条件クラスにより、特定のエラー型だけを選択的に捕捉できます
log_vec <- character(0)
withCallingHandlers({
  message('start')
  warning('low memory')
  message('end')
}, message = function(m) {
  log_vec <<- c(log_vec, paste('MSG:', trimws(m$message)))
  invokeRestart('muffleMessage')
}, warning = function(w) {
  log_vec <<- c(log_vec, paste('WARN:', w$message))
  invokeRestart('muffleWarning')
})
cat(log_vec, sep = '\n')

よくある質問

「withCallingHandlers()と再起動」レッスンは無料ですか?

はい。「withCallingHandlers()と再起動」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、R Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 R Academyコースには全4レッスンが含まれています。

「withCallingHandlers()と再起動」で何を学びますか?

withCallingHandlers()を使って、非局所的なコンディション処理を行います。 ブラウザで直接実行するハンズオンコードでR Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

R Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのR Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「withCallingHandlers()と再起動」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このR Academyレッスンでコードを書いて実行できますか?

はい。すべてのR Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Rのエラー、警告、メッセージ
  2. エラー回復のためのtryCatch()
  3. withCallingHandlers()と再起動
  4. stop()とwarning()による堅牢な関数の作成
← R Academyに戻る