18

Lispで暗黙のプログラミング(ポイントフリープログラミングとも呼ばれる)を使用/実装することは可能ですか? 答えが「はい」の場合、それは実行されていますか?

4

4 に答える 4

16

このスタイルのプログラミングは、原則として CL で可能ですが、Lisp-2 であるため、いくつか#'の とを追加する必要がありfuncallます。また、たとえば Haskell とは対照的に、関数は CL ではカリー化されておらず、暗黙的な部分適用はありません。一般に、そのようなスタイルはあまり慣用的な CL ではないと思います。

たとえば、部分適用と構成を次のように定義できます。

(defun partial (function &rest args)
  (lambda (&rest args2) (apply function (append args args2))))

(defun comp (&rest functions)
  (flet ((step (f g) (lambda (x) (funcall f (funcall g x)))))
    (reduce #'step functions :initial-value #'identity)))

(これらは私が思いついた簡単な例です。さまざまなユースケースについて実際にテストしたり、よく考えたりしたわけではありません。)

map ((*2) . (+1)) xsこれらにより、Haskellのようなものは次のようになります。

CL-USER> (mapcar (comp (partial #'* 2) #'1+) '(1 2 3))
(4 6 8)

sum例:

CL-USER> (defparameter *sum* (partial #'reduce #'+))
*SUM*
CL-USER> (funcall *sum* '(1 2 3))
6

(この例では、funcall を回避するために、関数を値セルに格納する代わりに、シンボルの関数セルを設定することもできます。)

ちなみにEmacs Lispでは、部分適用は として組み込まれていapply-partiallyます。

Qi/Shen では、関数はカリー化され、暗黙的な部分適用 (関数が 1 つの引数で呼び出される場合) がサポートされます。

(41-) (define comp F G -> (/. X (F (G X))))
comp

(42-) ((comp (* 2) (+ 1)) 1)
4

(43-) (map (comp (* 2) (+ 1)) [1 2 3])
[4 6 8]

Clojure には、「パイプライン処理」と同様の感覚を与えるシンタックス スレッド シュガーもあります。

user=> (-> 0 inc (* 2))
2
于 2012-06-17T19:57:00.087 に答える
8

->次のようなものを使用できます(これはClojureよりも少し多くなります):

(defmacro -> (obj &rest forms)
  "Similar to the -> macro from clojure, but with a tweak: if there is
  a $ symbol somewhere in the form, the object is not added as the
  first argument to the form, but instead replaces the $ symbol."
  (if forms
      (if (consp (car forms))
          (let* ((first-form (first forms))
                 (other-forms (rest forms))
                 (pos (position '$ first-form)))
            (if pos
                `(-> ,(append (subseq first-form 0 pos)
                              (list obj)
                              (subseq first-form (1+ pos)))
                     ,@other-forms)
                `(-> ,(list* (first first-form) obj (rest first-form))
                     ,@other-forms)))
          `(-> ,(list (car forms) obj)
               ,@(cdr forms)))
      obj))

$(配置するパッケージからシンボルをエクスポートすることにも注意する必要があります-->そのパッケージを呼び出しましょう-使用する予定のパッケージの句にtacit入れる ので、継承されます)tacituse->->$

使用例:

(-> "TEST"
    string-downcase
    reverse)

(-> "TEST"
    reverse
    (elt $ 1))

|>これは、HaskellよりもF# (およびシェルパイプ).に似ていますが、ほとんど同じです(私は好み|>ますが、これは個人的な好みの問題です)。

->が行われているのかを確認するには、最後の例を3回マクロ展開します(SLIMEでは、これは、例の最初(の例にカーソルを置き、3回入力することで実行されますC-c RET)。

于 2012-06-18T09:25:01.163 に答える
3

はい、それは可能であり、@danleiはすでに非常によく説明しています。関数ビルダーに関する第6.6章のPaulGrahamによる本ANSICommonLispからいくつかの例を追加します。

次のように関数ビルダーを定義できます。

(defun compose (&rest fns)
  (destructuring-bind (fn1 . rest) (reverse fns)
    #'(lambda (&rest args)
        (reduce #'(lambda (v f) (funcall f v))
                rest
                :initial-value (apply fn1 args)))))

(defun curry (fn &rest args)
  #'(lambda (&rest args2)
      (apply fn (append args args2))))

このように使用します

(mapcar (compose #'list #'round #'sqrt)
        '(4 9 16 25))

戻り値

((2) (3) (4) (5))

compose関数呼び出し:

(compose #'a #'b #'c)

と同等です

#'(lambda (&rest args) (a (b (apply #'c args))))

つまり、composeは任意の数の引数を取ることができます。

引数に3を追加する関数を作成します。

(curry #'+ 3)

本でもっと見てください。

于 2012-06-17T20:53:34.170 に答える
2

はい、これは一般的に適切な機能で可能です。たとえばsum、ウィキペディアのページからのRacket 実装の例を次に示します。

#lang racket
(define sum (curry foldr + 0))

プロシージャはデフォルトではカリー化されていないためcurry、明示的にカリー化されたスタイルで関数を使用または記述すると役立ちます。defineカリー化を使用する新しいマクロを使用して、これを抽象化できます。

于 2012-06-17T19:25:19.350 に答える