21

Python に Lisp/Scheme ( MetaPythonのようなもの) に似たマクロ機能があるとしたら、それをどのように使用しますか?

あなたが Lisp/Scheme プログラマーである場合、(while ループなどの Python で明確な構文上の類似性があるものを除いて) どんな種類のマクロを使用しますか?

4

16 に答える 16

15

マクロは Python の文化に反すると思います。Lisp のマクロは、大きな泥の塊のアプローチを可能にします。言語を再定義して、問題のドメインにより適したものにすることができます。逆に、Pythonic コードは、別の言語でより自然な方法で問題を解決するのではなく、Python の最も自然な組み込み機能を使用して問題を解決します。

マクロは本質的に非 Pythonic です。

于 2009-04-18T23:05:46.877 に答える
11

lispマクロのいくつかの例:

  • 面白くて拡張可能なループ機能であるITERATE
  • CL-コンパイル時にパーサーを生成するパーサージェネレーターであるYACC / FUCC
  • 静的部分と動的部分を含むhtmlドキュメントを指定できるCL-WHO
  • javascriptコードジェネレーターであるParenscript
  • さまざまな単純なコードラッパー、たとえば、エラーハンドラー(コードを実行し、未処理のエラーが発生した場合にGtkMessageDialogを表示するwith-gtk-error-message-handlerがあります)、実行者(たとえば、コードを指定して、別のスレッドで実行します。I異なるスレッドでコードを実行するメインスレッド内マクロがあります。PCallライブラリはマクロを使用して、同時に実行されるコードをラップします)
  • マクロを備えたGUIビルダー(たとえば、ウィジェットの階層とウィジェットのプロパティを指定し、すべてのウィジェットを作成するためのコードをマクロで生成する)
  • コンパイル時に外部リソースを使用するコードジェネレーター。たとえば、Cヘッダーを処理してFFIコードを生成するマクロ、またはデータベーススキーマに基づいてクラス定義を生成するマクロ
  • 宣言型FFI。たとえば、外部構造、関数、それらの引数タイプを指定し、対応するlisp構造を生成するマクロを使用する、タイプマッピングとマーシャリングコードを使用する関数
  • Common Lispの継続ベースのWebフレームワークは、コードをCPS(継続渡しスタイル)形式に変換するマクロを使用します。
于 2009-04-19T05:45:58.990 に答える
5

メーリング リストへの投稿( archive.org mirror ) で、これをかなりよく説明しています。この投稿は Perl に関するものですが、Python にも同様に当てはまります。

于 2009-04-18T23:01:42.923 に答える
4

Lisp では、マクロはアイデアを抽象化するもう 1 つの方法です。

これは、clojure で書かれた不完全なレイ トレーサーの例です。

(defmacro per-pixel
  "Macro.
Excecutes body for every pixel. Binds i and j to the current pixel coord."
  [i j & body]
  `(dotimes [~i @width]
     (dotimes [~j @height]
       ~@body)))

座標 (i,j) を持つすべてのピクセルに対して何かを行いたい場合、たとえば、i が偶数の場合に黒いピクセルを描画する場合は、次のように記述します。

(per-pixel i,j
  (if (even? i)
    (draw-black i,j)))

@body は内部のすべてを意味する可能性があるため、これはマクロなしでは実行できません (ピクセルごとの ij @body)

このようなことは、Pythonでも可能です。デコレータを使用する必要があります。Lisp マクロでできることすべてを行うことはできませんが、非常に強力です

このデコレーターのチュートリアルをチェックしてください: http://www.artima.com/weblogs/viewpost.jsp?thread=240808

于 2009-04-18T23:22:39.177 に答える
4

これは私が遭遇した実世界の例で、マクロまたは実際のメタプログラミングのサポートでは些細なことですが、Python には両方がないため、CPython バイトコード操作で実行する必要があります。

http://www.aminus.net/dejavu/chrome/common/doc/2.0a/html/intro.html#cpython

Common Lisp では、通常のマクロと read-macros を組み合わせて構文を拡張して問題を解決する方法を次に示します (後者がなくても実行できましたが、前者ではできませんでした)。

http://clsql.b9.com/manual/csql-find.html

クロージャーとメタプログラミングを使用して Smalltalk で同じ問題を解決しました (Smalltalk は、実際にメッセージ パッシングを正しく行う数少ないシングル ディスパッチ OO 言語の 1 つです)。

http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg02096.html

ここでは、Common Lisp で Smalltalk アプローチを実装しようとしました。これは、Common Lisp でのメタプログラミングのサポートが不十分であることを示す良い例です。

http://carcaddar.blogspot.com/2009/04/closure-directional-metaprogramming-via.html

于 2010-03-14T22:28:58.167 に答える
3

以前に見たいくつかのユース ケースには、クラス ファクトリの作成や、運用コードからのログステートメントの削除が含まれます。

于 2009-04-18T23:00:39.307 に答える
2

Python にマクロは必要ないと思います。マクロは次の 2 つの用途に役立つからです。

  1. 何かのために DSL またはより雄弁な構文を作成する (Lisp LOOP マクロは良い例です)。この場合、Python の哲学は、意図的に反対することを決定しました。不足している明示的な表記がある場合は、いつでも PEP を要求できます。

  2. コンパイル時に物事を事前計算することにより、物事を高速化します。Python は速度重視ではないため、代わりにいつでも関数を使用できます。

マクロが間違っていると言っているのではなく、マクロが Python の哲学に合わないというだけです。ダックタイピングと演算子のオーバーロードがあるため、多くのコード重複なしでいつでもそれらなしで行うことができます。

余談ですが、マクロよりも Lisp が Python で再起動されるのを見たいと思っています。

于 2009-04-19T07:05:08.690 に答える
1

ハイ、私自身の使用のために、引数、ループ、および条件付きコード生成を含むマクロ定義を可能にする Python モジュール (Espy) を作成しました。source.espy ファイルを作成し、適切な関数を起動すると、source.py が生成されます。

次のような構文を使用できます。

macro repeat(arg1):
    for i in range(%arg1%):
        socket
    print "stop"
   ...
repeat(5):
    print "Hi everybody"
    print "See you soon"

次と同等です。

...
for i in range(5):
    print "Hi everybody"
    print "See you soon"
print "stop"

その他の構文:

macro doit(arg1):
    for i in %arg1%:
        socket suit(arg2):
            socket
            print %arg2%
        socket check(arg3):
            if %arg2%==%arg3%:
                socket
...
#use
doit(range(10)):
    suit(result):
        result=i*i
    check(result,25):
        print "I knew that 5*5 == 25"

次と同等です。

for i in range(10):
    result=i*i
    print result
    if result==25:
        print "I knew that 5*5 == 25"

さらに、Espy には「macro for」と「macro if」の 2 つの機能があります。例:

macro for v in [6,10,12,20,23]:
    macro if 7<%v%<22:
        True:
            print "At %v%, I'm awake."
        False:
            print "At %v%, I'm sleeping."

は Espy によって次のように翻訳されています。

print "At 6, I'm sleeping."
print "At 10, I'm awake."
print "At 12, I'm awake."
print "At 20, I'm awake."
print "At 23, I'm sleeping."

完全なドキュメントと無料のダウンロードは、http: //elp.chronocv.frから入手できます。

多くの場合、このモジュールを使用します。これにより、より構造化された短いコードが可能になります。それを使用して、新しいチェス エンジン プロジェクト (まだ進行中) の 1000 行の espy コードから 65000 行の明確で効率的な Python コードを生成しました。

Python が将来のリリースでマクロを含めることができれば、より印象的なものになるでしょう。

于 2011-06-01T10:57:08.530 に答える
1

これを使用してラップyieldし、より強力なジェネレーター パイプラインを構築できるようにします。

于 2013-03-25T08:55:04.390 に答える
1

「The Lambda Papers」を読んで、なぜマクロを利用するのかを一般的に理解してください。

「AIM-353 Lambda: The Ultimate Imperative」から始めて、「AIM-443 Lambda: The Ultimate GOTO」に続いてください。両方ともここにあります:

http://library.readscheme.org/page1.html

于 2009-06-11T19:37:34.280 に答える
1

現在、言語の Python に機能を追加できる唯一の方法は、PEP (Python Enhancement Proposal) を使用することです。これは遅くなる可能性があり、ユースケースにのみ役立つ機能を言語に追加したい場合には役に立ちません。

たとえば、do-while ループを追加する PEP があります。これはおそらく Python に追加される予定ですが、PEP は 2003 年に作成されました。今日はループを書きたいと思いdo-whileます。Python にマクロがあれば、それが可能です。

同様に、ラベル付きの中断と継続を追加する PEPがありましたが、これは拒否されました。ラベル付きの break ステートメントを使用してコードをより明確にすることができれば、それらをマクロで実装できます。

PEP はさておき、unlessマクロも欲しいです。書くのではなく:

if not is_superman():
    dodge_bullet()

私は書くことができます:

unless is_superman():
    dodge_bullet()

caseマクロが欲しいです (Lisp でよく呼び出されcondます)。書くのではなく:

if x == FOO:
    do_stuff_with_foos()
elif x == BAR:
    do_stuff_with_bars()
elif x == BAZ:
    do_stuff_with_bazs()

私は書くことができます:

switch x:
   case FOO:
       do_stuff_with_foos()
   case BAR:
       do_stuff_with_bars()
   case BAZ:
       do_stuff_with_bazs()

これらは、マクロとして簡単に実装できます。より複雑で便利なマクロには、次のものがあります。

  • Ruby スタイルの文字列補間"hello there {user}"(おそらくリーダー マクロとして実装するのが最適)
  • パターンマッチング

現在、これらは他の言語の機能のみです。マクロを使えば、それらを Python に追加できます。実装例を含む PEP を書くことさえできました。(一部の PEP は既にこれを行っていますが、インタープリター自体の C ソースを変更することを余儀なくされています。)

于 2013-04-23T16:27:33.173 に答える
0

代わりに

print >> sys.stderr, "abc"

書く

err "abc"

多くのデバッグ出力ステートメントを持ついくつかのスクリプトで。

できます

import sys
err = sys.stderr

その後

print >> err, "abc"

これは短くなりますが、それでも行に多くの文字が必要です。

于 2012-04-10T05:51:02.123 に答える
0

C の世界から来た私は、リッチ メッセージを効率的にログに記録できることを本当に感謝しています。書く代わりに

if logger.level > logger.DEBUG:
    logger.log('%s' % (an_expensive_call_that_gives_useful_info(),))

マクロを使用すると、代わりに次のようなことができます

DEBUG('%s' % (an_expensive_call_that_gives_useful_info(),))
于 2014-03-11T18:53:32.070 に答える
0

おそらく、デバッグなどの実行時にソースコードが必要な場合(たとえば、式の値をその名前でprintfデバッグすると、2回書き込む必要がなくなります)。

Pythonでそれを行うために私が考えることができる唯一の方法は、文字列をevalに渡すことです。

于 2012-01-15T11:37:54.317 に答える