( define a ( vector 1 2 3 ))

( + ( vector-ref a 0 ) ( vector-ref a 1 ) ( vector-ref a 2 ))



( + a [ 0 ] a [ 1 ] a [ 2 ])



( + ( a _0 ) ( a _1 ) ( a _2 ))



( #%app + ( #%app a _0 ) ( #%app a _1 ) ( #%app a _2 ))



(v _n)

( define-syntax ( my-app stx )

( syntax-case stx ()

[( _ expr sub )

( and ( identifier? # ' sub )

( underscore-symbol? ( syntax-e # ' sub )))

( let* ([ sub ( remove-underscore ( syntax-e # ' sub ))]

[ num ( string->number ( symbol->string sub ))])

( cond

[( and ( number? num ) ( or ( zero? num ) ( positive? num )))

( quasisyntax/loc stx

( vector-ref expr # , ( datum->syntax-object # ' sub num )))]

[ else

( quasisyntax/loc stx

( vector-ref expr # , ( datum->syntax-object stx sub )))]))]

[( _ more ...)

# ' ( #%app more ...)]

[ _

( raise-syntax-error ' my-app "bad syntax, in ~a" stx )]))

(v _4)

v

vector-ref

vector-ref

quasisyntax/loc

( quasisyntax/loc stx

( vector-ref expr # , ( datum->syntax-object # ' sub num )))

_

syntax-case

[( __ expr _ sub )

( syntax/loc stx

( vector-ref expr sub ))]



(v 2 := 42)

(v _2 := 42)

( module vector-hack mzscheme

( provide ( rename my-app #%app ))



( begin-for-syntax

( define ( underscore-symbol? sym )

( and ( symbol? sym )

( let ([ str ( symbol->string sym )])

( > ( string-length str ) 0 )

( equal? ( string-ref str 0 ) #\_ ))))



( define ( remove-underscore sym )

( if ( underscore-symbol? sym )

( let ([ str ( symbol->string sym )])

( string->symbol ( substring str 1 ( string-length str ))))

( error ' remove-underscore "symbol doesn't start with an underscore: ~a" sym ))))





( define-syntax ( my-app stx )

( syntax-case stx ( _ := )

[( __ expr sub )

( and ( identifier? # ' sub )

( underscore-symbol? ( syntax-e # ' sub )))

( let* ([ sub ( remove-underscore ( syntax-e # ' sub ))]

[ num ( string->number ( symbol->string sub ))])

( cond

[( and ( number? num ) ( or ( zero? num ) ( positive? num )))

( quasisyntax/loc stx

( vector-ref expr # , ( datum->syntax-object # ' sub num )))]

[ else

( quasisyntax/loc stx

( vector-ref expr # , ( datum->syntax-object stx sub )))]))]

[( __ expr _ sub )

( syntax/loc stx

( vector-ref expr sub ))]

[( __ expr sub := value-expr )

( and ( identifier? # ' sub )

( underscore-symbol? ( syntax-e # ' sub )))

( let* ([ sub ( remove-underscore ( syntax-e # ' sub ))]

[ num ( string->number ( symbol->string sub ))])

( cond

[( and ( number? num ) ( or ( zero? num ) ( positive? num )))

( quasisyntax/loc stx

( vector-set! expr # , ( datum->syntax-object # ' sub num ) value-expr ))]

[ else

( quasisyntax/loc stx

( vector-set! expr # , ( datum->syntax-object stx sub ) value-expr ))]))]

[( __ expr sub := value-expr )

( syntax/loc stx

( vector-set! expr sub value-expr ))]

[( __ more ...)

# ' ( #%app more ...)]

[ __

( raise-syntax-error ' my-app "bad syntax, in ~a" stx )])))





( require vector-hack )

( define v ( vector 0 1 2 ))

( v _0 ) ( v _1 ) ( v _2 )

( define a 1 )

( v _a ) ( + ( v _0 ) ( v _1 ) ( v _2 ))

v ( v _0 := 3 ) v

( v 0 := 42 ) v







[Remember to leave a comment: Was this post silly? Enligthning? Old news?]"Scheme vector notation sucks" - a common complaint often heard amongst children and drunks. They might even be right. The sum of a three element vector is calculated like this:It looks like they are right. Can we repair this with some macro magic?Let's first consider what syntax we want to implement. Maybe something like this:Not bad, but in most Scheme implementations the parentheses () and [] mean the same.How aboutthen? That we can implement. In PLT Scheme the above is parsed as theapplication:All we need to do now, is to implement a new application, that takes special actionwhen the second argument begins with an underscore. In the following code underscore-symbol? is a function that checks whether a symbol starts with an underscore, and remove-underscore removes an initial underscore from a symbol.The code also handles the case where the subscript is an identifier, such as inNotice the use of quasisyntax/loc instead of plain quasisyntax.If a user writesandis of size 3, then an error must be signaled.The culprit is theexpression, so if plain quasisyntax is used,DrScheme will color theexpression red - and the user will thinkthe macro code is faulty. Usingallows us to report errorsto the usage of the macro.We also need a notation for the case, where the subscript is a general expression.That's fortunately easy. Addto the list of literals of theexpression, and add this clause:Finally we also need a convenient way to make assignments to vectors. The syntaxis easy to implement. And just in case people forget, we also supportThe entire source follows.Remember to leave a comment: Was this post silly? Enligthning? Old news?