あなたがもっと経験を積んでいない限り、Lisp で Haskell を書く方法ではなく、Lisp で Lisp を書く方法を学ぶことをお勧めします。後者は良い考えではありません。Haskell の動作は大きく異なります。
Lisp は「カリー化」(またはシェーンフィンケリング ;-)) を行いません。
次のように記述できます。
CL-USER 5 > (defun curry (fn arg) (lambda (&rest args) (apply fn arg args)))
CURRY
CL-USER 6 > (mapcar (curry #'expt 2) '(2 3 4 5 6))
(4 8 16 32 64)
ただし、その方法では少し効率が悪くなります。
CL-USER 7 > (mapcar (lambda (base) (expt base 2)) '(2 3 4 5 6))
(4 8 16 32 64)
私は個人的に後者を好みます。なぜなら、私は変数に実際に読みやすい名前を付けているからです。これは、バックトレースが表示されるデバッガーで役立ちます。このようなツールは、おそらく Haskell よりも Lisp の方が重要です。
CL-USER 12 > (mapcar (lambda (base) (expt base 2)) '(2 3 "four" 5 6))
エラー。バックトレースを見てみましょう:
CL-USER 12 : 1 > :bb
...
Condition: In EXPT of ("four" 2) arguments should be of type NUMBER.
Call to SYSTEM::ARGS-TO-BINARY-ARITHMETIC-FN-NOT-OF-TYPE {offset 189}
SYSTEM::FN-NAME : EXPT
SYSTEM::ARG1 : "four"
SYSTEM::ARG2 : 2
TYPE {Closing} : NUMBER
Interpreted call to (SUBFUNCTION :ANONYMOUS SYSTEM::ANONYMOUS-LAMBDA):
BASE : "four"
これで、物に名前があることがわかります。"four"
という名前の変数を使用して、文字列を関数に渡していましbase
た。
REPL とデバッグ ツールを使用したインタラクティブな開発が一般的です。この開発スタイルに役立つようにコードを準備してください。Common Lisp は、Haskell のように、広範な型チェックを備えた完全なプログラム コンパイラを提供するように最適化されていません。
Lispの主な問題の 1 つは、コードの一部が実際に何をしているのかを見つけるのが非常に難しいことです。デフォルト (プレフィックス構文を使用した厳密な関数型プログラム) は、比較的理解しやすいものです。しかし、Lisp のコードの意味を変更する可能性はたくさんあります (マクロ、読み取りマクロ、シンボル マクロ、メタ オブジェクト プロトコル、アドバイスなど)。
第 1 のルール: 基本的な Lisp コードを書いている場合は、基本的な構文と意味の可能性に固執してください。防御的に書く。他の誰かがコードを理解する必要があることを期待してください。そのためには、コードは読みやすく、理解しやすく、一般的なイディオムを使用し、デバッグ可能でなければなりません。
Haskell では、数学のバックグラウンドを持つ多くの人が、高度な抽象化を備えた非常にコンパクトな方法でコードを書きたいと考えています。Lispでもできます。しかし、通常のコードについては、私はその道をたどりませんし、より大きなコードの断片については、Lisp は他のメカニズム (マクロによるコード変換など) を使用することがよくあります。