(define-macro and
(lambda args
(if (null? args) #t
(if (null? (cdr args)) (car args)
(if (car args) `(and ,#(cdr args)) #f)))))
This is modified and macro, that is different on the last line. The correct way I know is correct is
`(if ,(car args) (and ,#(cdr args)) #f)))))
But I don't know how that change will affect the behavior of this macro.. I think it works the same, but if it doesn't, can you give an example when it won't?enter code here
So you have macro expansion time and you have runtime. Lets imagine that I use your first definition of and with (and (pair? lst) (cdr lst)). The code in effect is (if (car args) `(and ,#(cdr args)) #f)) and args are ((pair? lst) (cdr lst)). (car args) in macroexpansion time is (pair? lst) and it's not #f (anything except #f is true) but notice that you are not running (pair? lst), you are just assuring that I haven't written (and #f something). The code running in the function needs to make code and it doesn't have the data at run time rather it has the arguments as represented in source code.
By changing your last line to `(if ,(car args) (and ,#(cdr args)) #f))))) you are no longer checking if the data (pair? lst) is #f but it turns into (if (pair? lst) (and (cdr lst)) #f) and in runtime if will do consequent or alternative based on lst is a pair or not.
Related
Under Linux, eshell-autojump will do case sensitive matching which I just find a nuisance. I've tried to circumvent this by advising eshell/j with a eshell-under-windows-p that always returns t but to my chagrin eshell-under-windows-p invoked in eshell/j is unaffected by cl-letf. I've modified my eshell/j a bit to give me some debug info:
;; Modified eshell/j inside eshell-autojump.el to this
(defun eshell/j (&rest args) ; all but first ignored
"Jump to a directory you often cd to.
This compares the argument with the list of directories you usually jump to.
Without an argument, list the ten most common directories.
With a positive integer argument, list the n most common directories.
Otherwise, call `eshell/cd' with the result."
(setq args (eshell-flatten-list args))
(let ((path (car args))
(candidates (eshell-autojump-candidates))
(case-fold-search (eshell-under-windows-p))
result)
(when (not path)
(setq path 10))
(message "case-fold-search = %S" case-fold-search)
(message "eshell-under-windows-p returns %s from inside eshell/j" (eshell-under-windows-p))
(if (and (integerp path) (> path 0))
(progn
(let ((n (nthcdr (1- path) candidates)))
(when n
(setcdr n nil)))
(eshell-lisp-command (mapconcat 'identity candidates "\n")))
(while (and candidates (not result))
(if (string-match path (car candidates))
(setq result (car candidates))
(setq candidates (cdr candidates))))
(eshell/cd result))))
My init.el adds the advice to attempt to make eshell/j caseless by trying to trick it to think we are on Windows:
;; Added to init.el
(require 'eshell-autojump)
(advice-add 'eshell/j :around
(lambda (orig-fun &rest xs)
(cl-letf (((symbol-function 'eshell-under-windows-p) (lambda () t)))
(progn (message "eshell-under-windows-p returns %s from lambda" (eshell-under-windows-p)) (apply orig-fun xs)))))
But all I get in Messages buffer when I try to jump in eshell is:
;; I get in *Messages*
eshell-under-windows-p returns t from lambda
case-fold-search = nil
eshell-under-windows-p returns nil from inside eshell/j
My rookie knowledge of elisp is not enough to wrestle with probable scoping issues here. Can anyone decode why eshell-under-window-p is unaffected when called from eshell/j here?
I've found the answer. cl-letf does not work for byte compiled functions. As eshell-autojump is a package it gets byte compiled upon installation and cl-letf cannot be used to modify it's internal behavior. I had to resort to redefining the eshell/j which is a suboptimal solution.
I am developing a package that works from Emacs-22 called leaf, and I'd like to use macroexpand-1 when testing it
But macroexpand-1 was not defined in Emacs-22 and Emacs-26's the code could not be defined because it depends on 'C - based' autoload-do-load function, even if I try to define it.
Is it impossible to use macroexpand-1 in Emacs-22? A hint to implement
macroexpand-1 another way by Elisp is fine.
(Emacs-22 is bundled with macOS at /usr/bin/emacs)
see PR. https://github.com/conao3/leaf.el/pull/36/commits/47cf0b7c8d6b83b21800d01c594cef8e8d531e57
(when (not (fboundp 'autoload-do-load))
(defun autoload-do-load (fundef &optional funname macro-only)
(if (or (not (consp fundef)) (not (eql 'autoload (car fundef))))
fundef
(let ((kind (nth 4 fundef)))
(if (and (eql macro-only 'macro)
(not (or (eql kind t)
(eql kind 'macro))))
fundef)
(if purify-flag
(error "Attempt to autoload %s while preparing to dump" (symbol-name funnname)))
(unwind-protect
(let ((ignore-errors (if (or (eql kind t) (eql kind 'macro)) nil macro_only)))
(load (cadr fundef) ignore-errors t nil t))
;; FIXME: revert partially performed defuns
())
(if (or (not funname) ignore-errors)
nil
(let ((fun (indirect-function funname, nil)))
(if (equal fun fundef)
(error "Autoloading file %s failed to define function %s"
(caar load-history)
(symbol-name funname))
fun)))))))
Lisp newbie here.
I am reading Paul Graham's book, ANSI Common Lisp.
On page 38 is an uncompress function. It takes a list of pairs, where the first item in the pair is a number to indicate how many of the second item there should be. For example, uncompressing this:
((3 a) (2 b) c)
should produce this:
(A A A B B C)
I typed the uncompress function into a Lisp interpreter (GCL-2.6.2-ANSI) and then tested it like this:
(uncompress '((3 A) B (2 C) (5 D)))
That produced this error message:
Error in IF [or a callee]: Too many arguments.
Fast links are on: do (use-fast-links nil) for debugging
Broken at IF. Type :H for Help.
1 (Abort) Return to top level.
Below is the uncompress function. I think that I faithfully typed what was written in the book. I have tested each piece and each piece seems to work correctly. Truthfully, I'm stuck. I don't know what's causing the error. I'd appreciate your help.
(defun uncompress (lst)
(if (null lst)
nil
(let (elt (car lst))
(rest (uncompress (cdr lst))))
(if (consp elt)
(append (apply #'list-of elt)
rest)
(cons elt rest))))
(defun list-of (n elt)
(if (zerop n)
nil
(cons elt (list-of (- n 1) elt))))
If you use editor indentation tools, the code looks like this:
(defun uncompress (lst)
(if (null lst)
nil
(let (elt (car lst))
(rest (uncompress (cdr lst))))
(if (consp elt)
(append (apply #'list-of elt)
rest)
(cons elt rest))))
That would have made it easier to spot this error. Syntactically it is wrong, since the IF does not take more than three forms.
(defun uncompress (lst)
(if (null lst) ; the IF has four subforms, one too many
nil
(let (elt (car lst)) ;<- variables ELT and CAR? Makes no sense
(rest (uncompress (cdr lst)))) ; <- not using the result?
(if (consp elt) ; <- fourth form in IF? Does not make sense.
(append (apply #'list-of elt)
rest)
(cons elt rest))))
In Common Lisp both IF and LET are special operators with built-in syntax.
In Lisp the syntax for LET usually is:
let ({var | (var [init-form])}*) form* => result*
In Common Lisp it is possible to add declarations on top of the body forms of the LET:
let ({var | (var [init-form])}*) declaration* form* => result*
The syntax for IF in Common Lisp is:
if test-form then-form [else-form] => result*
Indentation
Generally it is not a good idea to manually indent Lisp code. Let the editor or IDE do it. Make sure that all code is properly indented.
If you have a syntax problem: first re-indent the expression -> this makes sure that the code is properly indented and then makes finding problems easier. Next compile the code and read the compiler error message. Common Lisp has great compilers and some have quite good error reporting.
The code
The code is not great anyway: it uses recursion where higher-order functions exist or a LOOP would be better
This version got both: the higher-order MAPCAN and a LOOP:
(defun uncompress (list)
(mapcan #'expand-item list))
(defun expand-item (item)
(typecase item
(atom (list item))
(cons (destructuring-bind (n element) item
(loop repeat n collect element)))))
You have the most typical common lisp syntax error: incorrect use of parentheses!
Here is the correct version:
(defun uncompress (lst)
(if (null lst)
nil
(let ((elt (car lst))
(rest (uncompress (cdr lst))))
(if (consp elt)
(append (apply #'list-of elt)
rest)
(cons elt rest)))))
Since these kind of errors are so common when no specialized editor is used, I advise you to use an editor like Emacs or Vim to edit your programs.
(defun magit-max-args-internal (function)
"Return the maximum number of arguments accepted by FUNCTION."
(if (symbolp function)
(setq function (symbol-function function)))
(if (subrp function)
(let ((max (cdr (subr-arity function))))
(if (eq 'many max)
most-positive-fixnum
max))
(if (eq 'macro (car-safe function))
(setq function (cdr function)))
(let ((arglist (if (byte-code-function-p function)
(aref function 0) ; <--------- format changed
(cadr function))))
(if (memq '&rest arglist)
most-positive-fixnum
(length (remq '&optional arglist))))))
I had to recompile magit.el and discovered this problem in their code. If I follow the code correctly, then what they were after here is the function's arity, but instead they are getting some "strange" number. Any ideas what happened?
In addition, this post: Elisp get function arity? offers a better solution (which does the job just fine, the answer by Andreas Röhler. So I will probably try to suggest it to magit maintainers.
Indeed this "number in (aref bytecode 0)" was introduced for lexical-binding. The better fix is to throw away magit-max-args-internal and use (condition-case nil (delete-directory <args>) (wrong-number-of-arguments (delete-directory <fewerargs>)) instead.
I'm trying understand how to interpret the output of, and use, the Lisp debugger.
I've got a pretty simple Backtrace for the evaluation of my function, but I cann't seem to work out how to use it to find out in which Lisp 'form' in my function the exception occurred.
I'd appreciate any clues as to what I should be doing, to find where in my code the error originated.
Also - why does the second frame display as "no debug information available for frame"?
I've attached a screen shot with the debugger, and repl (I've also included my function below - I know it's very wrong - but I'm just interested in learning to use the debugger properly). In addition, I hit 'v' on the first frame to go to the source, but this resulted in the error below the repl. (EDIT - the missing source code issue is fixed by downloading & copying it to the correct path)
(horrible function - no comments please!)
(defun myquicksort2 (lst)
(if (eql 1 (length lst))
lst
(let ((mid (middle lst)))
(do ((i 0 (+ i 1)))
((>= i mid) (append (myquicksort2 (subseq lst 0 mid))
(myquicksort2 (subseq lst mid (length lst)))))
(if (> (ltval i lst) (nth 100 lst))
(let ((tmp (ltval i lst)))
(setf (nth i lst) (gtval i lst))
(setf (nth (- (- (length lst) i) 1) lst) tmp)))))))
(defun ltval (i lst)
(nth i lst))
(defun gtval (i lst)
(nth (- (- (length lst) i) 1) lst))
(defun middle (lst)
(round (/ (length lst) 2)))
The error is with > and you have only one > in your source, so that's where the problem is.
edit Built-in CL functions are highly prone to optimization in SBCL, so although the function call in your code is to CL:<, the code that's actually called (and which shows up in the debugger) is from an optimized, specific, SBCL-internal routine. This is less of an issue for user-defined functions, where you will be much more likely to get a useful frame.