output n spaces in Common Lisp [duplicate] - format

I am looking for a way to output a character
a number of times using format. Is this possible? Can someone fill
in the _?_'s, so that the example works?
(let ((n 3))
(format nil "_?_" _?_ #\* _?_ ))
should return
=> "***"

It's nice to see so many solutions: ~A, ~<, and ~{ so far.
The ~#{ iteration construct provides a concise solution:
(format nil "~v#{~A~:*~}" 3 #\*)

(format nil "~a~:*~a~:*~a~:*" #\*)
"***"
Or elaborating a bit on Joshua Taylor's answer:
(format nil "~v{~a~:*~}" 3 '(#\*))
Would be one way of doing this. Don't be confused by the asterisks in the format directive, they are control characters, not characters being printed.
In terms of efficiency, however, this:
(make-string 3 :initial-element #\*)
would be a preferred way to achieve the same effect.

If you use the ~A directive, you can get this in exactly the form that you suggested, i.e.,
(let ((n 3))
(format nil "_?_" _?_ #\* _?_ ))
with three format arguments. However, if you use ~<, you can actually do this with just two format arguments. If you don't need this string inside of some other string that's already being generated by format, you could also just make the string using make-string.
Using Tilde A (~A)
You could print the character and specify a minimum width and the same character as the padding character. E.g., using ~v,,,vA and two arguments, you can ensure that some number of characters is printed, and what the padding character is.
CL-USER> (let ((n 3))
(format nil "~v,,,vA"
n ; number of characters that must be printed
#\* ; character to use as padding
#\*)) ; character to print with ~A
"***"
CL-USER> (let ((n 3))
(format nil "~v,,,vA" n #\* #\*))
"***"
CL-USER> (let ((n 10))
(format nil "~v,,,vA" n #\* #\*))
"**********"
This uses the full form of ~A:
~mincol,colinc,minpad,padcharA is the full form of ~A, which allows
control of the padding. The string is padded on the right (or on the
left if the # modifier is used) with at least minpad copies of
padchar; padding characters are then inserted colinc characters at a
time until the total width is at least mincol. The defaults are 0 for
mincol and minpad, 1 for colinc, and the space character for padchar.
as well as v:
In place of a prefix parameter to a directive, V (or v) can be used.
In this case, format takes an argument from args as a parameter to the
directive. The argument should be an integer or character. If the arg
used by a V parameter is nil, the effect is as if the parameter had
been omitted. # can be used in place of a prefix parameter; it
represents the number of args remaining to be processed. When used
within a recursive format, in the context of ~? or ~{, the # prefix
parameter represents the number of format arguments remaining within
the recursive call.
Using Tilde Less Than (~<)
There's also a less commonly used format directive, tilde less than, that's used for justification. it takes a format string and makes s
~mincol,colinc,minpad,padchar<str~>
This justifies the text produced by processing str within a field at
least mincol columns wide. str may be divided up into segments with
~;, in which case the spacing is evenly divided between the text
segments.
We can (ab)use this by passing an empty format string and just specifying the width and the padding character:
CL-USER> (let ((n 3))
(format nil "~v,,,v<~>"
n ; width
#\*)) ; padding character
"***"
CL-USER> (let ((n 5))
(format nil "~v,,,v<~>" n #\*))
"*****"
Just make a string
Of course, unless you need this special string inside of some other string that you're already formatting, you should do what wvxvw suggested, and just use make-string:
(make-string 3 :initial-element #\*)
Other alternatives
format is very flexible, and as this and other answers are pointing out, there are lots of ways to do this. I've tried to stick to ones that should do this in one pass and not do explicit iterations, but this can be done with format iterations, too, as Lars Brinkhoff and wvxvw have pointed out.

Like the answer of Lars, but we write the character wih ~C, instead of using the printer with ~A:
(format nil "~v#{~C~:*~}" 3 #\*)
Writing a character with something like write-char is a simpler operation than printing a Lisp object. The printer has a lot of context to observe and has to find the right way to print the object. OTOH, something like WRITE-CHAR just writes a single character to a stream.

Related

Lisp format list with parameter

I'm trying to create a function that will take a string and display it.
(defun closing (s)
(format t "~{~a~}" ("Sincerely," "\n" s)))
What I hope to get is
Sincerely,
Frank
if "Frank" is the string I passed in. It complains of the variable S is defined but never used. What am I doing wrong?
Trying to use format alone: If I declare urname as a defparameter to be "Frank", the following doesn't print Frank, rather just the variable name. (Without quote it complains of urname not being a function.)
(format t "~{~a~}" '(urname urname urname))
How can I feed variables to format?
There are three issues here: (1) The code you posted doesn't just have the problem of not using s; it's also trying to call the string "Sincerely" as a function; (2) quoting a list means you'll get exactly what's quoted (e.g., a list of symbols, not a list of values of variables); (3) calling format with lists.
(something other-stuff...) is a function call
When I put the code you posted into SBCL, I get some very specific and helpful output:
CL-USER> (defun closing (s)
(format t "~{~a~}" ("Sincerely," "\n" s)))
; in: DEFUN CLOSING
; ("Sincerely," "n" S)
;
; caught ERROR:
; illegal function call
; (SB-INT:NAMED-LAMBDA CLOSING
; (S)
; (BLOCK CLOSING (FORMAT T "~{~a~}" ("Sincerely," "n" S))))
;
; caught STYLE-WARNING:
; The variable S is defined but never used.
;
; compilation unit finished
; caught 1 ERROR condition
; caught 1 STYLE-WARNING condition
("Sincerely," "\n" s) is an illegal function call, since a string, like "Sincerely", can't have a function binding. Since SBCL sees the problem in that, it recognizes that the one thing that s might have been used for (i.e., an argument to a function call), can't happen. That's why you'll get the error, and then the associated style warning.
Creating lists of values
The second is probably answered in other questions already, but the short answer is that you want (list x y z), not '(x y z). The former calls the function list with the values of the variables x, y, and z, while the latter denotes a literal list of the symbols x, y, and z.
CL-USER> (let ((a 42)
(b 89))
(print '(a b)) ; a list of two symbols
(print (list a b))) ; a list of two numbers
(A B)
(42 89)
Format, iteration, &c.
The third is probably more interesting, since format has so many possibilities. The ~{ and ~} in your example are used for iterating over values in a list. First, let's look at a simple example: you can just use the format directive ~a and call format with the arguments you want to splice in:
CL-USER> (let ((closing "Sincerely")
(name "Frank"))
(format t "~a,~%~a" closing name))
Sincerely,
Frank
Now, if you need to print multiple values, you can use ~{ and ~} to have format iterate over a list of values:
CL-USER> (let ((closing "Sincerely")
(names '("Frank" "John")))
(format t "~a,~{~%~a~}" closing names))
Sincerely,
Frank
John
If the names are the values of variables, then you can either create a list containing those values:
CL-USER> (let ((closing "Sincerely")
(name1 "Frank")
(name2 "John"))
(format t "~a,~{~%~a~}" closing (list name1 name2)))
Sincerely,
Frank
John
or you can change ~{ to ~#{ and have format read the remaining arguments as the list:
CL-USER> (let ((closing "Sincerely")
(name1 "Frank")
(name2 "John"))
(format t "~a,~#{~%~a~}" closing name1 name2))
Sincerely,
Frank
John
You should read a tutorial about format, from here for example
For an easy explanation
(format
(destination-stream usually t for standard output nil to form a string)
(here comes the string)
(&rest variables that should write in the string where is an ~A and by position like String.format in java or c))
in your case, you need the symbol ~% or use the character for return in common lisp
CL-USER> (defun closing (s) (format t "~A~%~%~A" "Sincerely," s))
CLOSING
CL-USER> (closing "paco")
Sincerely,
paco
NIL
The nil say that the functions returns null, and the other is the standard output if you want to return a string, put nil instead of t

Floating point formatted to base 16

I am writing a Lisp program to approximate pi using a Spigot algorithm, one that finds a single digit at a time without needing any digits previously calculated. This one:
Supposedly goes one hexadecimal digit at a time, however testing it out we have consecutive calls (iterating over i) yielding Lisp's well-known fractions:
2F/F
6A/333
33D/4CB3
13C/3B79
And so forth. This is achieved using the format function with the ~x parameter:
(format t "~x" [some number])
Alternatively,
(format t "~d" [some number])
Yields the base 10 decimals:
3.1333334
0.12942614
0.042220525
0.020755336
However I want decimals in hexadecimal, for example if one round yielded 0.5 then I want 0.8; if the base 10 is 0.75 then I want 0.C. That way I can calculate see each hexadecimal digit of pi separately, which was my original reason for choosing this Spigot algorithm. I could also use a fraction of the form (n / 16^k), because this could easily be converted into a hexadecimal decimal.
Is this possible?
~x and ~d are formatting routines for integers, not floating point numbers (emphasis added):
22.3.2.2 Tilde D: Decimal
An arg, which should be an integer, is printed in decimal radix. ~D
will never put a decimal point after the number. … If arg is not an
integer, it is printed in ~A format and decimal base.
22.3.2.5 Tilde X: Hexadecimal
This is just like ~D but prints in hexadecimal radix (radix 16)
instead of decimal.
(As an aside, I think there's actually some ambiguity about what base ~x should print its argument in if it's not an integer. It comes down to whether "just like ~D but prints in hexadecimal" overrides just the integer arguments, or the all arguments.)
But what are these format directives actually doing? They're binding the values of *print-base* and *print-radix* and the documentation on those says that they only affect the printing of rational numbers:
Variable *PRINT-BASE*, *PRINT-RADIX*
*print-base* and *print-radix* control the printing of rationals. The value of *print-base* is called the current output base.
The value of *print-base* is the radix in which the printer will print
rationals. For radices above 10, letters of the alphabet are used to
represent digits above 9.
If the value of *print-radix* is true, the printer will print a radix
specifier to indicate the radix in which it is printing a rational
number. The radix specifier is always printed using lowercase letters.
If *print-base* is 2, 8, or 16, then the radix specifier used is #b,
#o, or #x, respectively. For integers, base ten is indicated by a trailing decimal point instead of a leading radix specifier; for
ratios, #10r is used.
Now, there are some floating point directives for format, and they're listed in 22.3.3 FORMAT Floating-Point Printers. Unfortunately, none of those do anything with different bases or radices, so you won't be able to print hexadecimals with them.
It looks like you'll end up having to write your own output routine, or find one in a library. Of course, you should probably implement it as a function that can be used with ~slash, so that you can still write things like:
(format t "~/hexadecimal/" 1/16)
It's actually not too hard to do this, so here's one way (but I won't guarantee that there are no bugs in this). It wouldn't be too hard to extend this to work with a user-provided base, and to make it a bit more like the other floating point printers (e.g., to add a + for positive numbers if # is provided, and to add support for widths, etc.).
(in-package #:common-lisp-user)
(defun hexadecimal (stream number colonp atp &rest args)
(declare (ignore colonp atp args))
(when (< number 0)
(write-char #\- stream)
(setq number (- number)))
(multiple-value-bind (quotient remainder) (floor number 1.0)
(format stream "~x." quotient)
(do () ((zerop remainder))
(multiple-value-setq (quotient remainder)
(floor (* 16 remainder)))
(format stream "~x" quotient))))
With this, you get the expected results:
(LOOP :FOR NUM :FROM -1/2 :TO 1/2 :BY 1/256
:COLLECT (FORMAT NIL "~/hexadecimal/" NUM))
;=>
("-0.8" "-0.7F" "-0.7E" "-0.7D" "-0.7C" "-0.7B" "-0.7A" "-0.79" "-0.78"
"-0.77" "-0.76" "-0.75" "-0.74" "-0.73" "-0.72" "-0.71" "-0.7" "-0.6F"
...
"-0.1D" "-0.1C" "-0.1B" "-0.1A" "-0.19" "-0.18" "-0.17" "-0.16" "-0.15"
"-0.14" "-0.13" "-0.12" "-0.11" "-0.1" "-0.0F" "-0.0E" "-0.0D" "-0.0C"
"-0.0B" "-0.0A" "-0.09" "-0.08" "-0.07" "-0.06" "-0.05" "-0.04" "-0.03"
"-0.02" "-0.01" "0." "0.01" "0.02" "0.03" "0.04" "0.05" "0.06" "0.07"
"0.08" "0.09" "0.0A" "0.0B" "0.0C" "0.0D" "0.0E" "0.0F" "0.1" "0.11"
...
"0.6C" "0.6D" "0.6E" "0.6F" "0.7" "0.71" "0.72" "0.73" "0.74" "0.75"
"0.76" "0.77" "0.78" "0.79" "0.7A" "0.7B" "0.7C" "0.7D" "0.7E" "0.7F"
"0.8")
In fact, it's really not hard to make this a bit more generic. Since we can pass arguments to format directives, we can take the printing base as an argument, and we can bind *print-base* to it at the same time, so we can just write in the body of the function, and we can do our numeric work with *print-base*:
(in-package #:common-lisp-user)
(defun floating (stream number colonp atp
&optional (*print-base* 10) (num-digits 10)
&rest args)
(declare (ignore colonp args))
;; If the number is negative, print the #\- and invert the number.
;; Otherwise, the number is non-negative, and if an # was provided
;; we print a leading #\+.
(cond
((minusp number)
(write-char #\- stream)
(setq number (- number)))
(atp
(write-char #\+ stream)))
;; Print number, which is now guaranteed to be positive. Begin by
;; taking its integer part and printing it, followed by a point.
;; Then, pull individual places and write them. This continues,
;; updating quotient and remainder by multiplying the remainder by
;; the base and taking the floor again until either the remainder
;; becomes zero, or we've reached the maximum number of digits.
(multiple-value-bind (quotient remainder) (floor number 1.0)
(write quotient :stream stream)
(write-char #\. stream)
(do ((num-digits num-digits (1- num-digits)))
((or (zerop remainder) (zerop num-digits)))
(multiple-value-setq (quotient remainder)
(floor (* *print-base* remainder)))
(write quotient :stream stream))))
;; 1/2 base 10 is a repeating decimal in base 3.
CL-USER> (format t "~3/floating/" 1/2)
0.1111111111
;; so is -1/2, and asking for more numbers gives them to us
CL-USER> (format t "~3,15/floating/" -1/2)
-0.111111111111111
;; but 1/3 base 10 is non repeating in base 3
CL-USER> (format t "~3,15/floating/" 1/3)
0.1
;; it's non-repeating in base 6, as well
CL-USER> (format t "~6,15/floating/" 1/3)
0.2
;; base 16 still works
CL-USER> (format t "~16/floating/" 189/256)
0.BD
;; and the # will give us a leading +
CL-USER> (format t "~16#/floating/" 189/256)
+0.BD
I don't think it is possible with the built in features of format1 However I'm sure someone with some fancy math could implement a function to do this.
1. I tested with SBCL v1.1.14. I tried (format t "~x" (coerce 2/32 'float)) which was the same as (format t "~d" (coerce 2/32 'float))

Lisp format a character a number of times

I am looking for a way to output a character
a number of times using format. Is this possible? Can someone fill
in the _?_'s, so that the example works?
(let ((n 3))
(format nil "_?_" _?_ #\* _?_ ))
should return
=> "***"
It's nice to see so many solutions: ~A, ~<, and ~{ so far.
The ~#{ iteration construct provides a concise solution:
(format nil "~v#{~A~:*~}" 3 #\*)
(format nil "~a~:*~a~:*~a~:*" #\*)
"***"
Or elaborating a bit on Joshua Taylor's answer:
(format nil "~v{~a~:*~}" 3 '(#\*))
Would be one way of doing this. Don't be confused by the asterisks in the format directive, they are control characters, not characters being printed.
In terms of efficiency, however, this:
(make-string 3 :initial-element #\*)
would be a preferred way to achieve the same effect.
If you use the ~A directive, you can get this in exactly the form that you suggested, i.e.,
(let ((n 3))
(format nil "_?_" _?_ #\* _?_ ))
with three format arguments. However, if you use ~<, you can actually do this with just two format arguments. If you don't need this string inside of some other string that's already being generated by format, you could also just make the string using make-string.
Using Tilde A (~A)
You could print the character and specify a minimum width and the same character as the padding character. E.g., using ~v,,,vA and two arguments, you can ensure that some number of characters is printed, and what the padding character is.
CL-USER> (let ((n 3))
(format nil "~v,,,vA"
n ; number of characters that must be printed
#\* ; character to use as padding
#\*)) ; character to print with ~A
"***"
CL-USER> (let ((n 3))
(format nil "~v,,,vA" n #\* #\*))
"***"
CL-USER> (let ((n 10))
(format nil "~v,,,vA" n #\* #\*))
"**********"
This uses the full form of ~A:
~mincol,colinc,minpad,padcharA is the full form of ~A, which allows
control of the padding. The string is padded on the right (or on the
left if the # modifier is used) with at least minpad copies of
padchar; padding characters are then inserted colinc characters at a
time until the total width is at least mincol. The defaults are 0 for
mincol and minpad, 1 for colinc, and the space character for padchar.
as well as v:
In place of a prefix parameter to a directive, V (or v) can be used.
In this case, format takes an argument from args as a parameter to the
directive. The argument should be an integer or character. If the arg
used by a V parameter is nil, the effect is as if the parameter had
been omitted. # can be used in place of a prefix parameter; it
represents the number of args remaining to be processed. When used
within a recursive format, in the context of ~? or ~{, the # prefix
parameter represents the number of format arguments remaining within
the recursive call.
Using Tilde Less Than (~<)
There's also a less commonly used format directive, tilde less than, that's used for justification. it takes a format string and makes s
~mincol,colinc,minpad,padchar<str~>
This justifies the text produced by processing str within a field at
least mincol columns wide. str may be divided up into segments with
~;, in which case the spacing is evenly divided between the text
segments.
We can (ab)use this by passing an empty format string and just specifying the width and the padding character:
CL-USER> (let ((n 3))
(format nil "~v,,,v<~>"
n ; width
#\*)) ; padding character
"***"
CL-USER> (let ((n 5))
(format nil "~v,,,v<~>" n #\*))
"*****"
Just make a string
Of course, unless you need this special string inside of some other string that you're already formatting, you should do what wvxvw suggested, and just use make-string:
(make-string 3 :initial-element #\*)
Other alternatives
format is very flexible, and as this and other answers are pointing out, there are lots of ways to do this. I've tried to stick to ones that should do this in one pass and not do explicit iterations, but this can be done with format iterations, too, as Lars Brinkhoff and wvxvw have pointed out.
Like the answer of Lars, but we write the character wih ~C, instead of using the printer with ~A:
(format nil "~v#{~C~:*~}" 3 #\*)
Writing a character with something like write-char is a simpler operation than printing a Lisp object. The printer has a lot of context to observe and has to find the right way to print the object. OTOH, something like WRITE-CHAR just writes a single character to a stream.

Scheme: Combining random and substring

I am trying to create a procedure that has a user input a non-empty string and then returns a random letter from the input in a substring of length one.
i.e.
(pick-at-random "word")
~"w"
(pick-at-random "word")
~"r"
So far I've got:
(define pick-at-random
(lambda (s)
(substring s (random(string-length s)) ())))
This gives me the position of the letter I want to display and I feel like where the () is, I should have some variable representing the start value of the substring and then add one to it. However, I don't know how to do this. Simply put, I am asking how I can limit the substring to length one while using the random function in the start value.
You may use let to bind the random number to a variable.
(define pick-at-random
(lambda (s)
(let ((index (random (string-length s))))
(substring s index (+ index 1)))))
Here's an alternative answer without using substring, in this way you don't need to save the index in a let binding. It's a more functional (and hence, idiomatic) solution to the problem:
(define (pick-at-random s) ; read the following lines from bottom to top
(string ; convert single character to string
(string-ref s ; access character in string, given an index
(random (string-length s))))) ; generate a random valid index in the string
(pick-at-random "word")
> "d" ; random result
The previous procedure generates a random valid index and then picks the character in that position within the string. As the last step, it turns back the single character into a string of length one.
The prior two answers are fine. Alternatively, you could break this problem into two problems:
Develop the function "nth-char" that accepts a word and an index, and returns a string containing the nth character of the word.
Develop the function "pick-at-random" that does what you describe. (Incidentally, I think a name such as "random-char" is somewhat better than "pick-at-random".)
This decomposition solves the problem you describe, by making it an argument to another function.
"Under the hood", this is the same solution as the one that uses "let".

Scheme recursion (decimal to octal)

So our class was given an assignment to convert decimal numbers to their octal representations. I managed to just tinker with it till it worked, but I'm having some problems comprehending why it works.
Any possibility at explaining the recursion in a more simplistic manner? Thanks.
(define octify
(lambda (n)
(cond
((zero? n) 0)
((zero? (quotient n 8)) n)
(else (+ (* 10 (octify (quotient n 8))) (remainder n 8))))))
First of all, a "number" is not decimal or octal. A "number" is a mathematical concept, which is stored in the computer in some sort of format with a bunch of bits. Decimal and octal refer to different string representations of a number. That is, "decimal" and "octal", etc. only make sense when talking about strings, and a particular number can be converted into a string as decimal or octal or whatever.
Producing the octal (or some other base) string representation of an integer is a common basic task in programming. The algorithm you have basically figured out: take the remainder of the number by the base to get the last digit, then recurse on the quotient of the number by the base to get the rest (all but last digit) of the number.
What is strange about what you are doing is that you are not producing a string, as one would normally do for this task. Instead, you are trying to pack it back into a number, in such a way that the resulting number's decimal representation would look like what the octal representation of the original number would look like. (This happens to be possible since any octal representation is also a valid decimal representation of some number. This wouldn't be possible with hex, for example.) In other words, you are converting a number to its octal string representation, then parsing that string into a number as if it were a decimal representation. For example, take the number 42, whose decimal representation is the string "42" and octal representation is the string "52". Your program returns the number 52 (whose octal representation is the string "64").
You may be confused because you are typing this into an interpreter, and when you compute or print a number, it outputs the decimal representation. But it is important to understand that a number is completely different from a string. (If you computed a string in your interpreter, perhaps it would surround it with quotes or something.) It would make most sense if your program outputted the string of the octal representation, rather than a number which when printed, looks like it.
The mainstream representation of number, the one that took the world by storm, is positional notation. It's a representation that's tied intimately with the concept of quotient and remainder operations, which you're seeing somewhat from your recursive function defintion. Why is that?
Let's take a quick aside: positional notation is not the only viable representation for number. One way that comes up every so often is a tallying approach, where a number is either zero or one more than a number. We can use sticks. Since we're talking about programs, let's use a data-type.
Number :== Zero
| Successor(n) where n is a number
Read this as "A number is either Zero, or the successor of another number". Or, to code it up in a Scheme that supports structured representations (like Racket), we can write this:
(define-struct Zero ())
(define-struct Successor (n))
For example, representing three with this notation would be (Successor (Successor (Successor (Zero))). (This representation is called Peano, if I'm remembering right.)
Functions that deal with this kind of structured datatype often have the same shape as that of the datatype itself. That is, a function that works on a representation in Peano will look something like this:
;; a peano-eating-function-template: peano-number -> ???
(define (a-peano-eating-function-template a-num)
(cond [(Zero? a-num)
...]
[(Successor? a-num)
...
(a-peano-eating-function-template (Successor-n a-num))
...]
where the ... will be something specific to the particular problem you're trying to solve on Peano numbers. It's a matter of functions following the structure of the data that they're working on. As an concrete example of a Peano-eating function, here's one that turns a piano into a bunch of stars:
;; peano->stars: peano-number -> string
;; Turn a peano in a string of stars. We are all made of stars.
(define (peano->stars a-num)
(cond [(Zero? a-num)
""]
[(Successor? a-num)
(string-append "*"
(peano->stars (Successor-n a-num)))]))
Anyway, so datatypes lead naturally to functions with particular shapes. This leads us to going back to positional notation. Can we capture positional notation as a datatype?
It turns out that we can! Positional notation, such as decimal notation, can be described in a way similar to how the Peano number description worked. Let's call this representation Base10, where it looks like this:
Base10 :== Zero
| NonZero(q, r) where q is a Base10, and r is a digit.
Digit :== ZeroD | OneD | TwoD | ... | NineD
And if we want to get concrete in terms of programming in a language with structures,
(define-struct Zero ())
(define-struct NonZero(q r))
(define-struct ZeroD ())
(define-struct OneD ())
(define-struct TwoD ())
(define-struct ThreeD ())
(define-struct FourD ())
;; ...
For example, the number forty-two can be represented in Base10 as:
(NonZero (NonZero (Zero) (FourD)) (TwoD))
Yikes. That looks a bit... insane. But let's lean on this a little more. As before, functions that deal with Base10 will often have a shape that matches Base10's structure:
;; a-number-eating-function-template: Base10 -> ???
(define (a-number-eating-function-template a-num)
(cond
[(Zero? a-num)
...]
[(NonZero? a-num)
... (a-number-eating-function-template (NonZero-q a-num))
... (NonZero-r a-num)]))
That is, we can get the shape of a recursive function that works on Base10 pretty much for free, just by following the structure of Base10 itself.
... But this is a crazy way to deal with numbers, right? Well... remember that wacky representation for forty-two:
(NonZero (NonZero (Zero) (FourD)) (TwoD))
Here's another way to represent the same number.
((0 * 10 + 4) * 10 + 2)
Pretty much the same idea. Here, let's get rid of a few more parentheses. We can represent forty-two with the following notation:
42
Our programming languages are hardcoded to know how to deal with this notation for numbers.
What's our equivalent for checking Zero? We know that one.
(= n 0) ;; or (zero? n)
What's our equivalent for checking NonZero? Easy!
(> n 0)
What are our equivalents for NonZero-q and NonZero-r?
(quotient n 10)
(remainder n 10)
Then, we can pretty much plug-and-play to get the shape of recursive functions that deal positionally with their numeric inputs.
(define (a-decimal-eating-function-template n)
(cond [(= n 0)
...]
[(> n 0)
... (a-decimal-eating-function-template (quotient n 10))
... (remainder n 10)]))
Look familiar? :)
For more of this, see a textbook like How to Design Programs.
Obviously, (octify 0) should be 0 and (octify n) for n such that 0 < n < 8 is n. The next condition is the complex one. The first question is "what does (octify (quotient n 8)) return?". With base-10 numbers, dividing by 10 removes the right-most digit - 145/10=14 (assuming integer division). With base-8 numbers, dividing by 8 works similarly. Therefore, (octify (quotient n 8)) returns a number with all but the last digit of n, assuming that octify is defined correctly (which we have to assume). Now, we need to take this number and "push" it a digit to the left. Multiplying it by 10 does this, since the printer will be printing it in base-10. (remainder n 8) gets the final digit of n. Now we have the first however many digits (with a zero for the final digit to go) and the final digit, so we can combine them by adding them. At this point, the function is done and the correct value is returned.

Resources