gusl: (Default)
[personal profile] gusl
One could use an expression like "~" to mark the expressions that one would like to trace when evaluated.

e.g.:
(defun analyze (group)
  (let* ((games (get-pairs group))
	 (scores (mapcar #'(lambda (game)
			     (progn (format t "~A:" game)
				    `(,game ,(read))~ )) ;; <--- THE ~ IS HERE!
			 games))
	 (table (make-table group scores)))
    (format t "~A~%" scores)))

would only print the result of the hidden "list" calls (quasiquote expands to (list game (read))).

I really think this would be better than the commonly-used solutions out there. Other tracing solutions:

* tracing functions: usually nice, except sometimes you only want to see the result of a particular call in the code, not all calls. Also, I sometimes wish I could define the condition on which the trace is shown... i.e. a test of the arguments.
* breakpoints: sometimes you don't want to trace, not break!
* copying expressions: awkward, non-modular, messy (need to be deleted later).
* assigning the value to a variable, printing it later: one can always substitute EXPR with (let ((temp EXPR)) (format t "~A~%" temp) temp). Maybe the ~ could be interpreted as a macro expanding to this.

(no subject)

Date: 2006-06-17 06:40 pm (UTC)
From: [identity profile] darius.livejournal.com
Not a bad idea. OTOH you could say (print `(,game ,(read))) since print returns its argument -- or make the ~ a read macro and place it before instead of after (which is more readable anyway, I think).

It would be pretty easy to define a TRACE-IF used like (trace-if 'function-name (lambda (arg1 arg2) (some-condition arg1))).

(no subject)

Date: 2006-06-17 06:50 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
<< OTOH you could say (print `(,game ,(read))) since print returns its argument >>

Thanks!


<< or make the ~ a read macro and place it before instead of after (which is more readable anyway, I think). >>

Is your suggestion this:

(defmacro ~ (expr)
  (print expr))
?

If so, this has two problems.

(1) it sucks to have to write the extra parentheses, as in
CL-USER> (~ `(,(+ 1 1) ,(+ 2 2)))
`(,(+ 1 1) ,(+ 2 2)) 
(2 4) 


(2) As you can see, the print is printing the expression raw, whereas we want to see it evaluated.

(no subject)

Date: 2006-06-17 06:55 pm (UTC)
From: [identity profile] darius.livejournal.com
Yeah, I just meant if you put the ~ before the expr instead of after, you wouldn't be fighting Lisp's syntax.

Use set-macro-character instead of defmacro, and have that expand it into something like (report 'expr expr) where you define REPORT as a function that displays the subject expression and the evaluated result in some nice way you like.

(no subject)

Date: 2006-06-17 07:25 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
CL-USER> (defun tilde-reader (stream char)
	   (declare (ignore char))
	   (let ((temp (read stream t nil t))) (format t "~A~%" temp) temp))
TILDE-READER
CL-USER> (set-macro-character #\~ #'tilde-reader)
T
CL-USER> ~(list (+ 1 1) (+ 2 2))
(LIST (+ 1 1) (+ 2 2))
(2 4)


Nice. This solves the extra parentheses problem! Now I just to figure out how to evaluate that stuff. Just doing eval won't work.

I take that back - eval does work

Date: 2006-06-17 07:41 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
CL-USER> (defun tilde-reader (stream char)
	   (declare (ignore char))
	   (let ((temp (read stream t nil t))) (format t "~A~%" (eval temp)) temp))
STYLE-WARNING: redefining TILDE-READER in DEFUN
TILDE-READER
CL-USER> (set-macro-character #\~ #'tilde-reader)
T

CL-USER> ~`(,(+ 1 1) ,(+ 2 2))
(2 4)
(2 4)


problem solved!

Date: 2006-06-17 10:42 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
(defun tilde-reader (stream char)
  (declare (ignore char))
  (print (eval (read stream t nil t))))


but I don't understand why this solution only evals once while the let-solution evals twice.

oops, still problematic!

Date: 2006-06-17 11:21 pm (UTC)
From: [identity profile] gustavolacerda.livejournal.com
I now that that in the right solution, the print should after the eval in the read-eval-print loop!

Re: oops, still problematic!

Date: 2006-06-18 02:51 am (UTC)
From: [identity profile] darius.livejournal.com
I was thinking like

? (set-macro-character #\~ (lambda (stream char) (let ((e (read stream))) `(report ',e ,e))))
;Compiler warnings :
;   Unused lexical variable CHAR, in an anonymous lambda form.
T
? (defun report (expr result) (print `(,expr => ,result)) result)
REPORT
? (report 'hello 42)

(HELLO => 42) 
42
? (+ ~(+ 2 3) 4)            

((+ 2 3) => 5) 
9
? 

Re: oops, still problematic!

Date: 2006-06-18 04:24 am (UTC)
From: [identity profile] gustavolacerda.livejournal.com
Great. Here's my own rendition of your idea, which works on my Lisp:

(defun tilde-reader (stream char)
  (let ((e (read stream)))
    `(rep ',e ,e)))

(defun rep (expr result) (format t "~A => ~A~%" expr result) result)

(set-macro-character #\~ #'tilde-reader)


I find it weird that tilde-reader returns a function call!

In other words, that set-macro-character takes a function returning a function call. But then again, isn't this how all macros are done?

Re: oops, still problematic!

Date: 2006-06-18 08:02 am (UTC)
From: [identity profile] darius.livejournal.com
Some people write their macros and read-macros to expand all the code inline, but I'd usually rather make the macro responsible only for syntax, with the actual functionality in functions. It's a useful discipline and the functions can be useful too -- in this case, it lets you redefine the reporting function instead of having to reload all your code to give the tildes a different expansion.

Profile

gusl: (Default)
gusl

December 2016

S M T W T F S
    123
45678910
11121314151617
18 192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags