Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tacit programming in Lisp

Is it possible to use/implement tacit programming (also known as point-free programming) in Lisp? And in case the answer is yes, has it been done?

like image 989
paldepind Avatar asked Jun 17 '12 17:06

paldepind


People also ask

What is a tacit programming language?

Tacit programming, also called point-free style, is a programming paradigm in which function definitions do not identify the arguments (or "points") on which they operate. Instead the definitions merely compose other functions, among which are combinators that manipulate the arguments.

What is point free code?

What is Point Free. Point free style is basically you write code but don't explicitly provide the arguments in the code. This is usefully especially in callbacks where a function is expected. I'll show you the examples in TypeScript, it'll work the same in JavaScript/ES6.

Is Common Lisp functional programming?

Lisp is a functional programming language with imperative features. By functional we mean that the overall style of the language is organized primarily around expressions and functions rather than statements and subroutines. Every Lisp expression returns some value.


1 Answers

This style of programming is possible in CL in principle, but, being a Lisp-2, one has to add several #'s and funcalls. Also, in contrast to Haskell for example, functions are not curried in CL, and there is no implicit partial application. In general, I think that such a style would not be very idiomatic CL.

For example, you could define partial application and composition like this:

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

(Those are just quick examples I whipped up – they are not really tested or well thought-through for different use-cases.)

With those, something like map ((*2) . (+1)) xs in Haskell becomes:

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

The sum example:

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

(In this example, you could also set the function cell of a symbol instead of storing the function in the value cell, in order to get around the funcall.)

In Emacs Lisp, by the way, partial application is built-in as apply-partially.

In Qi/Shen, functions are curried, and implicit partial application (when functions are called with one argument) is supported:

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

There is also syntactic threading sugar in Clojure that gives a similar feeling of "pipelining":

user=> (-> 0 inc (* 2))
2
like image 189
danlei Avatar answered Dec 28 '22 15:12

danlei