Programing Language: LISP Syntax Problem of Piping Functions

, ,

One of the annoying problem of the lisp nested syntax is the problem of creating a function chain (aka unix pipe, filtering, stream).

Here's a example i frequently encounter in emacs lisp. I want to apply several different functions to a string, one after the other. Example:

(setq fname (file-name-sans-extension (file-name-nondirectory fname)))
(setq fname (replace-regexp-in-string "-" " " fname))
(setq fname (replace-regexp-in-string "_002d" "-" fname))
fname

Note the repeated reset of a variable. I don't want that. I want to avoid mutable variables; it's bad in functional programing. 〔☛ Avoiding Variables in Functional Programing〕 So, one should do like this:

(replace-regexp-in-string "_002d" "-"
 (replace-regexp-in-string "-" " "
  (file-name-sans-extension
   (file-name-nondirectory fname))))

Here's a actual example, from https://github.com/ergoemacs/ergoemacs-mode/blob/master/ergoemacs-menus.el, by Matthew Fidler (he knows emacs lisp macro very well, since he implemented a whole key system in ergoemacs-mode using macros.).

(defun ergoemacs-kbd-to-key (key)
  "Convert key Emacs key code to ergoemacs-key-code."
  (let ((case-fold-search nil))
    (replace-regexp-in-string
     " " "  "
     (replace-regexp-in-string
      "<" ""
      (replace-regexp-in-string
       "?" ""
       (replace-regexp-in-string
        "\\bRET\\b" "ENTER"
        (replace-regexp-in-string
         "\\bprior\\b" "PgUp"
         (replace-regexp-in-string
          "\\bnext\\b" "PgDn"
          (replace-regexp-in-string
           "<f\\([0-9]+\\)>" "F\\1"
           (replace-regexp-in-string
            "\\b-\\b" "+"
            (replace-regexp-in-string
             "\\b[[:lower:]]\\b" 'upcase
             (replace-regexp-in-string
              "\\b\\([[:upper:]]\\)\\b" "Shift+\\1"
              (replace-regexp-in-string
               "\\bC-" "Ctrl+"
               (replace-regexp-in-string
                "\\bS-" "Shift+"
                (replace-regexp-in-string
                 "\\bM-" "Alt+"
                 key t) t) t) t) t) t) t) t) t) t) t) t) t)))

But that has several problems. It's hard to debug. Hard to re-order. Hard to manage. Also, in conventional lisp code formatting, “emacs-lisp-mode” would format it like this (expand your window width to prevent line wrapping):

(replace-regexp-in-string "_002d" "-"
                          (replace-regexp-in-string "-" " "
                                                    (file-name-sans-extension
                                                     (file-name-nondirectory fname))))

Alternative is a one-liner formatting, but it's hard to read and edit:

(replace-regexp-in-string "_002d" "-" (replace-regexp-in-string "-" " " (file-name-sans-extension (file-name-nondirectory fname))))

If lisp has adopted its early concept of M-expression as syntax wrapper, then it could be written like this using a postfix syntax like unix's pipe |. Here, i show it using Mathematica syntax:

fname //
file-name-nondirectory //
file-name-sans-extension //
Function[replace-regexp-in-string["-", " ", #]] //
Function[replace-regexp-in-string["_002d", "-", #]]

The // is similiar to unix's pipe | operator.

or in Mathematica's prefix notation, with @ as the prefix operator:

Function[replace-regexp-in-string["_002d", "-", #]] @
Function[replace-regexp-in-string["-", " ", #]] @
file-name-sans-extension @
file-name-nondirectory @
fname

Note that in functional languages (⁖ Haskell, OCaml), they have both prefix and postfix operators. Usually the space character is used as context-sensitive implicit prefix operator. ⁖ f x means “f” applied to “x”, and f a b c means (((f a) b) c). In Ruby, Perl, usually they have postfix operator desguised as calling object's methods. In perl, it's ->, in Ruby, it's just a dot ..

For detail, see:

Also note, although Haskell and OCaml have postfix and prefix operators, but these lang's syntax in general are syntax soups. That is, it's one bunch of ad hoc designs with no consistency, no systematic grammar, no mathematical foundation. They are not much better than the syntax soup of C-like langs. The symbols are used promiscuously (see: Problems of Symbol Congestion in Computer Languages; ASCII Jam vs Unicode) and the forms are idiosyncratic, ⁖ i++, ++i, for(;;){}, while(){}, 0x123, expr1 ? expr2 : expr3, sprint(…%s…,…), …. The only language i know whose syntax approaches a systematic grammar is Mathematica. See: Concepts & Confusions of {Prefix, Infix, Postfix, Fully Nested} NotationsMath Notations, Computer Languages, and the “Form” in Formalism.

Lisp Solution

one solution, available in some lisp such as scheme lisp shell scsh, is this:

(| f g h)
blog comments powered by Disqus