de-vraag
  • 質問
  • タグ
  • ユーザー
通知:
報酬:
登録
登録すると、質問に対する返答やコメントが通知されます。
ログイン
すでにアカウントをお持ちの方は、ログインして新しい通知を確認してください。
追加された質問、回答、コメントには報酬があります。
さらに
ソース
編集
ゲストユーザ
質問

レキシカル環境からカスタム関数を取得できるようにする

私はレキシカルバインディングを使用するように自分のコードを変換しようとしています。

ユーザがカスタマイズ可能なリスト( template-replace)からラムダ関数( replacer-inner へのlet-bound)を呼び出す関数( format-template マッチ文字列に基づいた関数の関数(-functions )です。 replacer-inner関数は引数を取らずに文字列を返しますが、変数 foo bar および/または baz は list の引数の一部として format-template に渡されます。

(setq lexical-binding t)

(defcustom template-replace-functions
  '(("email"
     (lambda () user-mail-address)
    ("apples"
     (lambda ()
       (cond ((= foo 1)
              "one")
             ((= foo 2)
              "two")
             ((= foo 3)
              "three")
             (t "four"))))
    ("bananas"
     (lambda ()
       (if (eq bar 'move)
           "movement" "sit still")))))
  "Association list of replacement functions.

For each STRING, the corresponding FUNCTION is called with no
arguments and must return a string."
  :type '(repeat (group string function))
  :group 'spice-girls)

(defun format-template (list)
  (let* ((foo (nth 0 list))
         (bar (nth 1 list))
         (baz (nth 2 list))
         template
         (replacer-outer
          (lambda ()
            (replace-regexp-in-string
             "\${\([^\s\t\n]*?\)}"
             (lambda (match)
               (let* ((key (match-string 1 match))
                      (replacer-inner
                       (cadr (assoc key template-replace-functions))))
                 (if (and replacer-inner
                          (stringp (funcall replacer-inner)))
                     (funcall replacer-inner) "")))
             template t t))))
    (setq template
          ...)
    (if template (funcall replacer-outer))))

たとえば、 list には bar と baz にレットバインドされた3つの要素が含まれています。 match-stringのキーは、 template-replace-functions の関数に関連する "bananas" 内部には:

(lambda ()
       (if (eq bar 'move)
           "movement" "sit still"))

この時点で、上記のラムダ関数は、動的バインディングを使っても問題ないが、字句バインディングを使ってうまくいくわけではない bar を知る必要があります。

私の質問は、lambda関数が foo bar のlet-bound値から取る replacer-inner baz ?

( replace-inner を含む replace-outer 関数は、実際の関数の2つの場所のいずれかから呼び出されるため、何かを混乱させるだけです。私はここでインラインで書くことができたかもしれませんが、問題に追加する場合は、この方法でインクルードしました。)

編集:

途中で...

(setq lexical-binding t
  foo 0
  bar 0)

(setq inline-fun-1
      '(lambda ()
         (setq return
               (if (eq foo 1)
                   "Pass" "Fail"))))

(defmacro lex-fun ()
  `(let* ((foo 1)
          (bar 1)
          return)
     (funcall ,inline-fun-1)))

(lex-fun)    ; -> "Pass"

(defun inline-fun-2 ()
  (setq return
        (if (eq bar 1)
            "Pass" "Fail")))

(defmacro lex-fun ()
  `(let* ((foo 1)
          (bar 1)
          return)
     (funcall ,inline-fun-2)))

(lex-fun)    ; -> Lisp error: (void-variable inline-fun-2)

したがって、マクロ内のラムダ関数を拡張すると動作するように見えますが、名前付き関数ではありません。しかし、私はユーザーのラムダまたは名前付きの関数を許可したいです。これを回避するには?

3 2016-02-26T07:24:49+00:00 1
Emacs
lexical-scoping
Yann Trevin
26日 2月 2016 в 12:22
2016-02-26T12:22:26+00:00
さらに
ソース
編集
#56789005

短い答え:できません。これが、この種のバインディングが「字句」と呼ばれる理由です。変数が定義域から逃げるのを防ぎます。

この問題に対処する方法の1つは、バナナがバナナの値を抽出する方法を知っている「バナナ」関数にデータ構造を渡すことができたということです。私。

(defcustom template-replace-functions
  '(("bananas" . (lambda (env) 
                   (let ((x (gethash "x" env "")))
                     (do-replacements-with x))))
    ...)))

これは、 env がハッシュテーブルであることを前提としています。

さて、 eq ではなく eql を使用する方が良いでしょう。私はEmacs Lispがどのようなタイプのデータでも eq の振る舞いをどのように保証しているとは思わない(例えば、同じ名前のインターンシンボルも< code> eq )。

1
0
質問の追加
カテゴリ
すべて
技術情報
文化・レクリエーション
生活・芸術
科学
プロフェッショナル
事業内容
ユーザー
すべて
新しい
人気
1
Roxana Elizabeth CASTILLO Avalos
登録済み 1週間前
2
Hideo Nakagawa
登録済み 1週間前
3
Sergiy Tytarenko
登録済み 1週間前
4
shoxrux azadov
登録済み 1週間前
5
Koreets Koreytsev
登録済み 2週間前
© de-vraag :年
ソース
emacs.stackexchange.com
ライセンス cc by-sa 3.0 帰属