Lisp的隐性编程(Tacit programming in Lisp)

2019-07-30 00:07发布

是否有可能使用/实施默契编程用Lisp(也称为自由点编程)? 而如果答案是肯定的,有没有做过?

Answer 1:

这种编程方式是可能的CL原则,但是,作为一个Lisp-2,必须加上几个#' S和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

在齐/沉,功能咖喱,和隐式部分应用程序(当函数调用使用一个参数)被支撑:

(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


Answer 2:

你可以使用类似(这是做多一点-> 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任何包装的where子句中要使用-> ,所以->$继承)

用法示例:

(-> "TEST"
    string-downcase
    reverse)

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

这更像是F#的|>和壳管),比Haskell的. ,但他们几乎是同样的事情(我喜欢|>但是这是个人喜好的问题)。

要查看->在做什么,只是macroexpand最后一个例子三次(粘液,这是通过将第一光标完成(在本例中和打字Cc RET三次)。



Answer 3:

是的,这可能和@danlei已经解释得非常好。 我会从书ANSI Common Lisp的由保罗·格雷厄姆,在功能建设者6.6章加起来一些例子:

你可以定义一个函数生成器是这样的:

(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)

被equlvalent到

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

这意味着撰写可以采取任何数量的参数,是的。

让其中新增3至自变量的函数:

(curry #'+ 3)

查看更多的书。



Answer 4:

是的,这是可能的,一般用正确的功能。 例如,这里是拍实施的例子sum从维基百科页面:

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

由于程序默认情况下不令行禁止,它有助于使用curry或显式咖喱风格写你的函数。 你可以抽象在这一个新的define ,使用钻营宏。



文章来源: Tacit programming in Lisp