Giter Club home page Giter Club logo

fear-of-macros's People

Contributors

cmpitg avatar greghendershott avatar leafac avatar marckaufmann avatar offby1 avatar stonecauldron avatar tautologico avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fear-of-macros's Issues

Error in section 4.3 dot notation macro

If I use the macro code for accessing a nested hash table using hash.key.key I notice some lexical scope errors:

;; works as expected
(define js (hasheq 'a (hasheq 'b (hasheq 'c "value0"))))
(hash.refs js.a.b.c)
;; oops! does not access the let bound js, but instead the top level js
(let ((js (hasheq 'a (hasheq 'b (hasheq 'c "value1")))))
  (hash.refs js.a.b.c))
;; unbound identifier error
(let ((js2 (hasheq 'a (hasheq 'b (hasheq 'c "value2")))))
  (hash.refs js2.a.b.c))

I believe the fix could be:

(define-syntax (hash.refs stx)    
  (syntax-case stx ()      
    ; If the optional ‘default' is missing, assume it's #f.
    [(_ chain)
     ;; *** we need to keep the syntax context from the original input syntax, not generate 
     ;; *** a new syntax context with the macro recursion
     (datum->syntax stx (syntax->datum #'(hash.refs chain #f)))]
    [(_ chain default)
     (let ([xs (map (lambda (x) (datum->syntax stx (string->symbol x)))
                    (regexp-split #rx"\\." (symbol->string (syntax->datum #'chain))))])
       (with-syntax ([h (car xs)]
                     [ks (cdr xs)])
         #'(hash-refs h 'ks default)))]))

But I'm not sure how to replace (datum->syntax stx (syntax->datum #'(hash.refs chain #f)) with something a little more racketish or descriptive.

Thanks for writing this, it's been quite useful in my learning process.

Emacs comment in Section 4.1

There is a note about DrRacket's Macro Expander:

Even if you prefer mostly to use Emacs, this is a situation where it’s definitely worth temporarily using DrRacket for its Macro Stepper.

I just happened to start using your Emacs racket-mode macro expander functionality just yesterday, and read Fear of Macros for the first time today. I think the macro expander in racket-mode works great! Maybe the comment could plug racket-mode, because for me at least, I see no reason to leave Emacs while debugging macros.

Thanks for this

Not an issue, I just wanted to say thank you for writing this. I've really been enjoying it over the last few days.

Zen saying translation is incorrect

I believe the middle part of the translation in the epilogue is incorrect. The code
(not (and (eq? 'mountains 'mountains)
(eq? 'rivers 'rivers)))
is equivalent (semantically) to "mountains are not mountains, OR rivers are not rivers",
whereas the actual words are: "mountains are not mountains, AND rivers are not rivers"

P.S. Sorry for bothering you, I just thought it would be funny to mention the fact.

Comments

our-if-v2 should use first, second, third, etc because the c(a|d)*rs are confusing

3.5 - define-syntax inside of begin-for-syntax doesn't mean what you think it means. That defines a macro for the syntax-phase (the syntax-syntax-phase) not a macro for the runtime-phase. The macro wouldn't be able to refer to the helper.

4 - syntax-parse came after match (but syntax-case came before)

4 - the switch from match to syntax-case also starts using #' rather than datum->syntax which is another big change (re hygiene)

5 - I think the use of make-rename-transformer needs explanation

Fix `stx` args in section 4.1

Examples using datum->syntax and format-id in section 4.1 work when the macro is used directly, but don't work when the macro is used by another macro.

From IRC chat:

Re http://paste.lisp.org/display/139228 the tl;dr seems to be that this line is wrong:

    (with-syntax ([hyphen-datum (datum->syntax stx hyphen-symbol)])

Instead change stx to body0:

    (with-syntax ([hyphen-datum (datum->syntax body0 hyphen-symbol)])

That way, when the macro is used by another macro, the correct lexical scope is being used. So it looks like I need to:

  1. Change that example in Fear of Macros.
  2. Make sure I can explain clearly why this matters (hint: see http://jeapostrophe.github.io/2013-07-22-123list-post.html).
  3. Probably start a section like "Macro-Generating Macros".

The code from pastebin:

#lang racket

(require (for-syntax racket/syntax
                     racket/string))

(define-syntax (hyph stx)
  (syntax-case stx ()
    [(_ (names ...) (args ...)
        body0
        body ...)
     (let* ([syntax-list (syntax->list #'(names ...))]
            [symbol-list (map syntax-e syntax-list)]
            [string-list (map symbol->string symbol-list)]
            [hyphen-string (string-join string-list "-")]
            [hyphen-symbol (string->symbol hyphen-string)])
       (with-syntax ([hyphen-datum (datum->syntax stx hyphen-symbol)]) ;; <-- CHANGE THIS
         #'(define (hyphen-datum args ...)
             body0
             body ...)))]))

(define-syntax (get/set stx)
  (syntax-case stx ()
    [(_ field-name init-value)
     #'(begin
         (define field-name init-value)
         (hyph (set field-name) (value)
               (set! field-name value))
         (hyph (get field-name) ()
               field-name))]))

(get/set gogo "dancer")
(get-gogo)
(set-gogo "all clear")
(get-gogo) 
=>

4-sandbox.rkt:32:1: get-gogo: unbound identifier in module
  in: get-gogo

syntax-case: unbound identifier

When I tried to compile the first example in Section 4 I got the error: syntax-case: unbound identifier in the transformer environment; also, no #%app syntax transformer is bound

To fix this, I added (require (for-syntax racket/base)) to the top of my file. (The corrected version is at the bottom of this issue.) Two questions:

  1. Is this the correct fix?
  2. Did I miss a pre-requisite explanation in the tutorial?

For reference, I'm using Racket 6.1.1.4

#lang racket/base

(require (for-syntax racket/base))
(define-syntax (our-if-using-syntax-case stx)
    (syntax-case stx ()
      [(_ condition true-expr false-expr)
       #'(cond [condition true-expr]
               [else false-expr])]))

(our-if-using-syntax-case #t "true" "false")

[question][3.1]having difficult time understanding define-syntax?

First of all, thanks for making this! :-)

So on 3.1 where it talks about define-syntax with example:

(define-syntax foo
    (lambda (stx)
        (syntax "I am foo")))

it explains that:

When we use define-syntax, we’re making a transformer binding. This tells the Racket compiler, "Whenever you encounter a chunk of syntax starting with foo, please give it to my transformer function, and replace it with the syntax I give back to you." So Racket will give anything that looks like (foo ...) to our function, and we can return new syntax to use instead. Much like a search-and-replace.

My questions:

What does it mean that "a syntax starting with foo"? What is a syntax? Do you mean the syntax object that is introduced on section 3.2, that's something with lexical environment and code location and s-expression etc? Or is that some other conceptual thing or is that a specific language construct? If the syntax mentioned here here is the syntax object that's mentioned in 3.2, then what could a chunk of syntax mean here? It reads more like a piece of textual code then a set of language constructs(which is syntax object).. So I am not really sure what exactly the syntax mean here.

I am not sure what makes define-syntax different here either? But I guess once I get what syntax mean here then define-syntax makes some sense too?

Code mismatch in section 3.4

In section 3.4 the 'our-if-v2' code and the step by step breakdown after it don't match up. In the second line of the function 'xs' is defined using 'syntax->list', but in the step by step breakdown 'xs' is defined using 'syntax->datum'. If there's no reason for the change then they should be made the same, and if there is a reason then a footnote explaining why would help clarify.

(define-syntax (our-if-v2 stx)
    (define xs (syntax->list stx)) ;1
    (datum->syntax stx `(cond [,(cadr xs) ,(caddr xs)]
                              [else ,(cadddr xs)])))

(define xs (syntax->datum stx)) ;2

anophoric if example

Working my way through this tutorial; thanks!

Section 5 ends with "But we can still define it as a normal variable" and an example of doing so. It doesn't mention that after one has defined it as a normal variable, "aif" no longer works:
syntax-parameterize: not bound as a syntax parameter in: it

I tried to fix this by putting the define-syntax-parameter in a local scope around the body of the macro definition:

(define-syntax aif
(local ((define-syntax-parameter it ; etc.))
(lambda (stx)
(syntax-case ; etc.))))

but apparently define-syntax-parameter doesn't count as a "definition" for local's purposes. And I suspect that if it were defined only locally, it wouldn't serve the intended purpose anyway.

Backtick & comma introduced w/o explanation

In section 3.4, you introduce ` and , in the our-if-v2 macro. I know about the interplay of ` and , from fooling around with Common Lisp a bit, but that was the first I've seen them used in Racket (still very new), and some people may not understand their use at that point in your tutorial.

Katakana misspelling of “Transformer”

Section 3.1's amusing pop culture reference to the Transformers media franchise and its Japanese roots transliterates “Transformer” as トランスフォーマ (toransufōma), converting the “-er” into a short /a/ when it should be a long /aː/ (toransufōmā). The correct spelling has an additional ー on the end: トランスフォーマー.

format-id examples are sloppy

@lexi-lambda in a Stack Overflow answer:

To fix this, change your call to format-id so that it creates an identifier with the same scope as the operation identifier rather than the surrounding syntax object:

(format-id #'oper "iex-~a" #'oper)

...

Arguably, some of the examples in Fear of Macros that use format-id are sloppy in this respect. It might be worth trying to improve them to set a better example.

pdf

Hi Greg,

Very nice. As I plan to read the rest on the train, would it be possible to have a link for the pdf or a 1-page HTML?

Thanks,
Laurent

Typo in README

The Feedback section title has a typo in it (says Feeback).

Inconsistent fonts for code and output

Maybe it's just some Safari settings I need to change, but in trying to read on my IPhone, I'm seeing big variations in size for the code (sometimes small, sometimes big), and the output (ditto). I'm having to a lot of pinching and stretching.

Very useful tutorial, thanks.

Clarification on datum->syntax first argument

First of all thank you for having taken the time to write this guide about macros; it has proven immensely helpful.

In section 3.3 (transformers section) it would be helpful to briefly explain the purpose of the first argument in datum->syntax. The racket reference can be a bit overwhelming for beginners in the language.

unbounded chain in revised hash.refs macros, section 4.3

In the error-handling version of hash.refs in 4.3, in:

; Check for no args at all
[(_)
 (raise-syntax-error #f "Expected hash.key0[.key1 ...] [default]" stx #'chain)]

the chain variable is not bound in the pattern for this case, so the whole sub-expr argument for raise-syntax-error should probably be omitted:

 (raise-syntax-error #f "Expected hash.key0[.key1 ...] [default]" stx)]

Archival URL?

I'd like to cite your work in a book I'm writing. But personal URLs are notoriously short-lived. Would you be willing to upload PDF to arxiv.org, or some similar location?

(I saw the open PDF issue #3. If it would help to have somebody try the build on Linux, I'm happy to try.)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.