Claude Code Plugins

Community-maintained marketplace

Feedback

cl-condition-system

@cxxxr/.claude
1
0

condition/restartパターンを適用。エラーハンドリング実装時に使用

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name cl-condition-system
description condition/restartパターンを適用。エラーハンドリング実装時に使用
allowed-tools Read, Grep, Glob

Common Lisp Condition System

基本概念

Common Lispの条件システムは、エラー処理を「通知」と「回復」に分離する強力な機構です。

概念 役割
Condition エラーや状態を表すオブジェクト
Handler 条件を検知して対応を決定
Restart 回復手段を提供

条件の定義

基本的な条件

(define-condition invalid-input-error (error)
  ((input :initarg :input :reader invalid-input)
   (reason :initarg :reason :reader invalid-input-reason))
  (:report (lambda (condition stream)
             (format stream "Invalid input ~S: ~A"
                     (invalid-input condition)
                     (invalid-input-reason condition)))))

条件の階層

;; 基底条件
(define-condition my-app-error (error)
  ((context :initarg :context :reader error-context)))

;; 特殊化
(define-condition database-error (my-app-error)
  ((query :initarg :query :reader error-query)))

(define-condition connection-error (database-error)
  ((host :initarg :host :reader error-host)))

重大度別の基底クラス

基底クラス 用途
error 回復必須のエラー
warning 警告(処理は継続)
simple-condition 単純な状態通知

Restart の提供

restart-case パターン

(defun parse-config (path)
  (restart-case
      (let ((content (read-file path)))
        (if (valid-config-p content)
            (parse content)
            (error 'invalid-config-error :path path)))

    (use-default ()
      :report "Use default configuration"
      *default-config*)

    (retry-with-path (new-path)
      :report "Try a different config file"
      :interactive (lambda ()
                     (format t "Enter new path: ")
                     (list (read-line)))
      (parse-config new-path))

    (skip ()
      :report "Skip configuration loading"
      nil)))

標準リスタート

;; abort - 処理を中止
(restart-case
    (risky-operation)
  (abort ()
    :report "Abort the operation"
    nil))

;; continue - 処理を続行
(restart-case
    (when (suspicious-p data)
      (cerror "Continue anyway" "Suspicious data detected"))
  (continue ()
    :report "Continue processing"))

;; use-value - 代替値を使用
(restart-case
    (or (get-value key) (error 'missing-key :key key))
  (use-value (value)
    :report "Use a specific value"
    :interactive (lambda () (list (read)))
    value))

Handler の設定

handler-bind

条件発生時に呼ばれるが、スタックは巻き戻されない。

(handler-bind
    ((invalid-input-error
       (lambda (c)
         (log:warn "Invalid input: ~A" (invalid-input c))
         (invoke-restart 'use-default)))
     (warning
       (lambda (c)
         (log:info "Warning: ~A" c)
         (muffle-warning c))))
  (process-user-input input))

handler-case

条件発生時にスタックを巻き戻してハンドラを実行。

(handler-case
    (parse-and-process input)
  (invalid-input-error (c)
    (format t "Error: ~A~%" c)
    nil)
  (file-error (c)
    (format t "File error: ~A~%" c)
    (retry-with-default))
  (error (c)
    (log:error "Unexpected error: ~A" c)
    (error c)))  ; 再通知

使い分け

状況 使用
リスタートを呼び出したい handler-bind
単純なエラー処理 handler-case
ロギングのみ handler-bind
クリーンアップ必要 handler-case + unwind-protect

実践パターン

パターン1: リトライ機構

(defun fetch-with-retry (url &key (max-retries 3))
  (loop for attempt from 1 to max-retries
        do (restart-case
               (return (http-get url))
             (retry ()
               :report "Retry the request"
               (log:info "Retry attempt ~D" attempt)
               (sleep (* attempt 2))))  ; バックオフ
        finally (error 'max-retries-exceeded :url url)))

;; 使用側
(handler-bind
    ((connection-error
       (lambda (c)
         (when (find-restart 'retry)
           (invoke-restart 'retry)))))
  (fetch-with-retry "https://api.example.com"))

パターン2: バリデーション

(defun validate-user (user)
  (restart-case
      (progn
        (unless (valid-email-p (user-email user))
          (error 'validation-error :field 'email))
        (unless (strong-password-p (user-password user))
          (error 'validation-error :field 'password))
        user)
    (fix-field (field value)
      :report "Fix the invalid field"
      (setf (slot-value user field) value)
      (validate-user user))))

パターン3: トランザクション

(defun with-transaction (thunk)
  (let ((tx (begin-transaction)))
    (restart-case
        (prog1 (funcall thunk tx)
          (commit tx))
      (rollback ()
        :report "Rollback transaction"
        (rollback tx)
        nil)
      (retry ()
        :report "Retry transaction"
        (rollback tx)
        (with-transaction thunk)))))

デバッグ

利用可能なリスタートの確認

(compute-restarts)           ; 全リスタート
(find-restart 'retry)        ; 特定リスタート
(invoke-restart-interactively 'use-value)  ; 対話的に呼び出し

デバッガでの操作

;; SBCLデバッガ内
0: [RETRY] Retry the operation
1: [USE-DEFAULT] Use default value
2: [ABORT] Abort

;; 数字を入力してリスタートを選択