-
Notifications
You must be signed in to change notification settings - Fork 0
/
utilities.lisp
105 lines (93 loc) · 3.02 KB
/
utilities.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
;;;; utlilities.lisp
(in-package :ros-utils)
(defmacro printout->string (&body body)
"Given a body, returns as a string any
printout produced by the body."
(let ((str (gensym "STR-STREAM")))
`(with-output-to-string (,str)
(let ((*standard-output* ,str))
,@body))))
(defmacro broadcast-printout
((&optional
(file-name "quicklisp/local-projects/rosetta/printout.txt.lisp"))
&body body)
"Given an optional filename and body, returns any printout
produced by the body as a string and
writes it to a file."
(with-gensyms (string-stream file-stream)
`(with-output-to-string (,string-stream)
(with-open-file (,file-stream
,file-name
:direction :output
:if-does-not-exist :create
:if-exists :overwrite)
(let ((*standard-output*
(make-broadcast-stream
,string-stream
,file-stream)))
,@body)))))
(defmacro abbrev (short long)
"Given two symbols, the second of which
is an interned symbol (presumably one
with a long name) that is assigned
an operator, assign the same operator
to the first (presumably shorter)
symbol."
`(defmacro ,short (&rest args)
`(,',long ,@args)))
(defmacro abbrevs (&rest names)
"Given a series of pairs of symbols,
assign the first symbol in each pair
the same operator already assigned to
the second symbol in each pair."
`(progn
,@(mapcar #'(lambda (pair)
`(abbrev ,@pair))
(batches names 2))))
(abbrevs
mbind multiple-value-bind
dbind destructuring-bind)
(defun rationalize (x)
"Given a real number, return
a rational number whose
value is identical to the
displayed value of the reat
(rather than the binary
approximation.) This is a
native CL function, but for some
reason it does not work as advertised
in ECL on Android."
(assert (realp x)
()
"RATIONALIZE takes a real argument, not %A %S."
(type-of x) x)
(if (rationalp x)
x
(do* ((nstr (format nil "~F" x))
(len (length nstr))
(mantissa 0)
(i 0 (1+ i))
(divider 1)
(sign 1)
(zero-code (char-code #\0))
(point-seen nil))
((= i len)
(* sign (/ mantissa divider)))
(let ((c (char nstr i)))
(case c
(#\+ nil)
(#\- (setf sign -1))
(#\. (setf point-seen t))
(otherwise ; c is a digit char
(let ((val
(- (char-code c)
zero-code)))
(setf mantissa
(+
(* mantissa 10)
(if (minusp mantissa)
(- val)
val)))
(when point-seen
(setf divider
(* divider 10))))))))))