Sometimes a closing parenthesis is on a line by itself:
(defun foo ()
...
)
(let ((x y)
(z w)
)
...)
Historically, it's not been unheard of that Lisp experts (even implementors) do this sort of thing. Exhibit A, randomly picked source file inside CLISP:http://sourceforge.net/p/clisp/clisp/ci/default/tree/src/clo...
Some of Xah's indentation is inconsistent:
(function
(one space)
indent like data)
(function
(two space indent)
like code))
Not too much stands out otherwise; the code is readable.I'd have to read deeper to see whether things that are usually done one way are done differently for no good reason. What I would consider "unidiomatic" would be, for instance:
(if (not (null list)) ...)
rather than (if list ...)
(Any Lisp dialect requiring code such the former is labelled differently, namely "idiotic".)[0]: http://ergoemacs.org/emacs/elisp_grep_string_inside_tag.html
Now you might think that this is also unidiomatic:
(setq totalCnt (1+ totalCnt))
Turns out, though, that Elisp doesn't have modify macros, except in the CL compatibility package.What Xah is doing is the same as the accepted SO answer for incrementing a local variable:
http://stackoverflow.com/questions/6858894/how-to-increment-...
On the setq, I what I meant was iterating through setqs and while (and I seem to recall even catch/throw) as agumonkey mentioned.
Then again, 'in my mind', idiomatic elisp uses cl-lib :D. so (cl-incf total-count) would be better. snakeCase is unidiomatic as well.
[0]: https://www.reddit.com/r/lisp/comments/29ufoc/it_is_not_hard...
About Scheme's regexp SRFI, have you seen rx.el? Not quite but I like it myself.
lispm point is nice (and no one can argue about evaluation order and count), but beside the battle-tested aspect, `loop` scares the crap out of me. That's even more a reason to prefer things that avoids it in my mind, mentally small building blocks and patterns versus huge macro-based sublanguages. Yes general and probably super-efficiently implemented, but .. nah.
(defvar xah-left-brackets '("(" "{" "[" "<" "〔" "【" "〖" "〈" "《" "「" "『" "“" "‘" "‹" "«" )
"List of left bracket chars.")
(progn
;; make xah-left-brackets based on xah-brackets
(setq xah-left-brackets '())
(dotimes (x (- (length xah-brackets) 1))
(when (= (% x 2) 0)
(push (char-to-string (elt xah-brackets x))
xah-left-brackets)))
(setq xah-left-brackets (reverse xah-left-brackets)))
(defvar xah-right-brackets '(")" "]" "}" ">" "〕" "】" "〗" "〉" "》" "」" "』" "”" "’" "›" "»")
"list of right bracket chars.")
(progn
(setq xah-right-brackets '())
(dotimes (x (- (length xah-brackets) 1))
(when (= (% x 2) 1)
(push (char-to-string (elt xah-brackets x))
xah-right-brackets)))
(setq xah-right-brackets (reverse xah-right-brackets)))
In CL this is just: (defun every-nth (seq start n &aux (len (length seq)))
(loop for i = start then (+ i n)
while (< i len)
collect (elt seq i)))
(defvar xah-left-brackets (every-nth xah-brackets 0 2))
(defvar xah-right-brackets (every-nth xah-brackets 1 2))
Write useful building blocks. Don't duplicate code. Get rid of low level imperative code.Bonus points for a more efficient version for lists.
(defun ab (l)
"I'm too lazy to reverse the result back."
(defun _ (l a b f)
(if (null l)
(if f (list a b) (list b a))
(_ (cdr l) b (cons (car l) a) (not f))))
(_ l nil nil t))
(ab '())
(ab '(1))
(ab '(1 2))
(ab '(1 2 3 4 5 6 7 8 9 10))
;; ((9 7 5 3 1) (10 8 6 4 2))
(ab '(1 2 3 4 5 6 7 8 9 10 11))
;; ((11 9 7 5 3 1) (10 8 6 4 2))
I don't know how cute or ugly a solution for variable step could be though. `ab` is a nice partitioning building block, less general than every-nth surely.ps: Straight from the land of wishful lisping
(defun abn (l n)
(defun ono (n)
"builds a cons oo cycle of size n"
'unicorn)
(defun noo (c)
"rotates a cons cycle by one"
'unicorn)
(defun cooons (c v)
"cons v to the head of c"
'unicorn)
(defun _ (l c)
(if (null l)
c
(_ (cdr l) (noo (cooons c (car l))))))
(_ l (ono n)))I'd avoid recursive code like that as much as possible.
I'd write:
(defun ab (l)
(loop while l collect (pop l) into a
while l collect (pop l) into b
finally (return (list a b))))Your last example is nice. I had to read the CLHS loop to have a clue about linearity of multiple termination clauses though :)
ps: funny, while googling I even found some lisp checker with a rule about nested defuns (## define-lisp-pattern nested-defuns)
http://www.cs.northwestern.edu/academics/courses/325/program...
#lang racket
(define-syntax-rule (defun name (arg ...) . body)
(define (name arg ...) . body))
(define nil null)
(define t #t)
(defun ab (l)
;; "I'm too lazy to reverse the result back."
(defun _ (l a b f)
(if (null? l)
(if f (list a b) (list b a))
(_ (cdr l) b (cons (car l) a) (not f))))
(_ l nil nil t))
(ab '())
(ab '(1))
(ab '(1 2))
(ab '(1 2 3 4 5 6 7 8 9 10))
;; ((9 7 5 3 1) (10 8 6 4 2))
(ab '(1 2 3 4 5 6 7 8 9 10 11))
;; ((11 9 7 5 3 1) (10 8 6 4 2))
...and you don't need to worry about recursion limits thanks to mandatory TCO. $ txr -i
1> (defvarl brackets '("(" ")" "[" "]" "<" ">")))
brackets
2> [brackets (range 0 : 2)]
("(" "[" "<")
3> [brackets (range 1 : 2)]
(")" "]" ">")
range generates lazy list of integers with a step size (the colon symbol defaults the second upper bound argument so the list is infinite). A list of integers can be used in the brackets notation to select elements. Put the two together and you have spaced selection.Regarding defvarl, there is defvar too; defvarl means that the symbol is not marked special and so rebindings are lexical. Often, it is overkill for a global variable to support rebinding. We just pollute the symbol with the special marker and then have to namespace it or put earmuffs on it just in case, even though it is ever used that way.
(let (var1 (var2 0))
(when condition
(setq var1 (var1-initializer-form))
...)))
is just silly. Only the inner scope of the when uses var1, or any of the vars; it could just be: (when condition
(let ((var1 (var1-initializer-form))
(var2 0))
...))
Never do two-step initialization of a variable without an excellent reason; it's just sloppy otherwise.Yeah, but for idiots like me who sometimes make mistakes, having a type system that catches errors for me helps sometimes. There are plenty of times in languages that treat null as false-y where I've put completely the wrong variable in and gotten no useful feedback from my interpreter because it type-checks just fine and the error doesn't become apparent until 50 lines of code later in a completely different function.
Besides, if you're frequently writing code like this, it's probably because you don't understand what you're doing and are working at the wrong level of abstraction for your problem. If you're recursing over items in a list, it's almost certain you should be using a higher-order function.
This is sort of funny coming from a guy who isn't using the shift key properly. Language conventions make communication easy. It's why $_ should be used. It's why "ain't" isn't a word and the subject comes before the verb.