RU beehive logo ITEC dept promo banner
ITEC 380
2016fall
ibarland

homelecturesrecipeexamshwsD2Lbreeze (snow day; distance)

backquote
backquote

quote

In racket, 'x is a symbol. However, there's another viewpoint (usually used by common-lispers): 'x is a "quoted identifier", and it's equivalent to (quote x). The special form quote simply returns its input, un-processed.

Returning something un-evaluated can be applied to more than just identifiers: (quote 7) evaluates to 7, and (quote "hello") to "hello". Thus, there isn't really any reason to write those (nor their shorthand '7 or '"hello"), but you could if you wanted. We mention this only to understand how quoting works with lists, below.

quoting a list

What does it mean to return a list, un-evaluated? It means "don't treat it as a function call". '(sqrt 25) (or equivalently, (quote (sqrt 25))) evaluates to (list 'sqrt 25) — a list containing a symbol and a number.

Furthermore, the quote is actually recursively mapped to each element of the list: '(sqrt (+ 20 2 3)) returns (list 'sqrt (list '+ 20 2 3)) — a list containing two items, where the second item is a (sub)list.

This is handy, if you want to make (nested) lists, and don't want to have to keep calling list yourself. For example, it's not uncommon to keep a list of name/value pairs: '((amy 7) (ian 5) (sammy 9) (eric 8)) is more convenient to write than (list (list 'amy 7) (list 'ian 5) (list 'sammy 9) (list 'eric 8)) (but they are both equivalent). This is especially true when the listing can be arbitrarily deep. Suppose you want to represent HTML tags as a list with the tag-name followed by their contents (strings and other tags):

'(html (head (title "backquoting, explained"))
       (body (h1 "How to Quote")
             (p "In racket, " (tt "'x") " is a symbol.")))
   
rather than
(list 'html
      (list 'head
            (list 'title "backquoting, explained"))
      (list 'body
            (list 'h1 "How to Quote")
            (list 'p
                  "In racket, " 
                  (list 'tt "'x")
                  " is a symbol.")))
   
Note that when we deep-map the “'” over the list, the quote applied to strings "disappears", e.g. '"How to Quote" evaluates immediately to the (unquoted) string "How to Quote". However, the interior bits like body are quoted to become the symbol 'body.

By the way, such lists are a convenient way to represent XML, especially if you add in an association-list of attributes and attribute-values. See “X-expressions”. The one drawback of using this for XML is that we find ourselves writing lots of double-quote-marks for strings. See “@-expressions” for a notation to help with that.

quoting expressions

Lispers like to point out the beautiful symmetry: take any racket/lisp code, throw a quote on the front of it, and now you have the program-source, as data! In essence, the S-expression is the syntax-tree of the code. This means you can manipulate it yourself — for example, write a program that walks through the expression and returns a new (different-but-related) expression. This is the idea behind macros.

Indeed, there is a lisp/scheme/racket function eval which takes such a quoted-list, and evaluates it as if it were racket code, and gives you the result: (eval '(sqrt (+ 20 2 3))) returns 5. (In racket, eval takes a second argument — the namespace to evaluate the expression in — important if you don't want to eval something which re-defines names your own program is using.

read

backquote and unquote

Using quote (“'”) to quote your data is nice. But the true power comes in the form of backquote, “`”.

Recall the example: '((amy 7) (ian 5) (sammy 9) (eric 8)). But what if we wanted to compute the value associated with each name? If we use backquote, then any interior expression that is preceded by unquote (“,”) is evaluated again:

(define x 5)
`((amy ,(+ 2 5)) (ian ,x) (sammy ,(+ x (string-length "sammy") -1)) (eric 8))

Unquoting/re-quoting nests, exactly like you'd expect:

`((amy ,(+ 2 5))
  (ian ,(assoc 'hello '((bye 3) (hello 5) (aloha 5))))
  (sammy ,(+ (string-length "ciao") (assoc 'hello `((bye 3) (hello ,x) (aloha 5)))))
  (eric 8))
  

This is remiscent of switching between text-mode and php-mode in php programs, except they can't nest. In php, your file starts in text-mode, and then enter php-mode with a processing instruction “<?php ?>”. But inside the , then you can't enter a “sub”-text mode; instead you have leave php-mode. This leads to unsavory stuff like:

This is text mode
<?php $greeting = "hello"; ?>
and we want to say
<?php if (strlen($greeting) === 3) {
  echo $greeting;
  ?>
Ugh, now we're back in top-level text mode, but we're also in the middle of a php `if`!
<?php } else {?>
Okay, now back in text mode again.  This just <em;>feels</em> wrong.
It's bad enough when you think about copying/pasting code that
has possibly-dangling php structure, or trying to write automated-tools for
detecting php errors.
When you realize that it's common to require/include other files
which have dangling php blocks, it just makes you want to cry.
#phpsadness (.com).
<?php }?>
  


Quote and backquote, applied to P0

The following discussion refers to ways you might want to use backquote in the particular example of implementing ../Homeworks/Project/P0.html.

#|
Note:
The 'cond' has a bunch of repeated patterns that it'd be nice to factor out.
The first pass would have the cond just choose +,*,-, and we'd apply the result:
((cond [(string=? (bin-expr-op e) "add") +]
       [(string=? (bin-expr-op e) "mul") *]
       [(string=? (bin-expr-op e) "sub") -])
  left-value
  right-value))

This is pretty good, but we can do better.  Imagine we had a 'lookup' function:
((lookup (bin-expr-op e) (list (list "add" +)
                               (list "mul" *)
                               (list "sub" -)))
     left-value
     right-value))

; Turns out lookup isn't *quite* built in, 
; but it's easy to make, out of "association lists"
; and the built-in function 'assoc'
;
(define (lookup key a-list) (second (assoc key a-list)))
;  Or just :   (define lookup (compose second assoc))

; I'll leave it for further reading, about how 'assoc' works exactly.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Digression: backquote, unquote:
We saw that a quote can be used to make a symbol:   'hello
And now, a secret: If you try to "quote a list", the quote distributes over the list:
'(3 4 hi 8)  =  (list 3 4 'hi 8)   ; (Note that 'hi is quoted)
It even works recursively:
'(3 4 (5 6 bye 7) hi 8)  = (list 3 4 (list 5 6 'bye 7) 'hi 8)
                  ; That's a list-of-length-five, the middle of which is itself a list-of-length-four.

;  "Lisp" = "list processing"
;
; Back to quoting a list: What if one of the things in the list is a variable, like pi?
'(hi 3 "howdy" pi)  =  (list 'hi 3 "howdy" 'pi)
; Rats, we get the *symbol* 'pi (just like we did for 'hi), not 3.14.
; 
; THe cool solution: We can use back-quote, which allows *unquote* (comma):
`(hi 3 "howdy" ,pi) = (list 'hi 3 "howdy" 3.14159)
; We can unquote *any* expression:
`(hi 3 "howdy" ,(* pi 100))  = (list 'hi 3 "howdy" 314.159)
;
; Anything being unquoted is a perfectly fine expression.
; It might even contain a backquote itself (which can of course contain an unquote (comma) ...

`(hi 3 ,(map sqrt `(16 25 ,(* 100 pi))) "hello")  = ???

; [typographically, note how command and backquote do look kinda opposite/mirror-image...]
; Once you've digested all that, you can read about unquote-splice.

; Note that quoting a list, unquote and unquote splice
; All get rewritten into (primitive)quote-symbol, `list`, and `append` functions.
; They're just shortcuts -- handy, but nothing we couldn't do before.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


Where were we?
Oh right, 
((lookup (bin-expr-op e) (list (list "add" +)
                               (list "mul" *)
                               (list "sub" -)))
     left-value
     right-value))

The association-list (list of key/value pairs) can be written more concisely using backquote:

((lookup (bin-expr-op e) `(("add" ,+)
                           ("mul" ,*)
                           ("sub" ,-)))
     left-value
     right-value))

; Note that that (a) we really need the comma there:
;  we want the list to contain the-actual-multiplication-function,
;  not just an asterisk-symbol.
; and (b) an association-list containing functions is very convenient
; (esp. w/ λ).


|#

1 This is true in both Lisp and in racket/scheme; it's just that the racketeers/schemers prefer to think of the symbol as an end-value, whereas lispers prefer to think of it as unevaluated-lisp-code. With all due deference, the lispers have it a bit wrong.      

2 Most programmers would view it as a serious safety flaw, if running code modified (at run-time) their own functions. But others delight at the thought of self-modifying code. It's fun as a toy, but not what you want in a language (like, say, javascript...).      

homelecturesrecipeexamshwsD2Lbreeze (snow day; distance)


©2016, Ian Barland, Radford University
Last modified 2016.Nov.11 (Fri)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Rendered by Racket.