Scheme macro pairwise processing question - macros

(For now please ignore that what I'm after is un-Schemey, because this for a DSL aimed at non-programmers)
I'd like to do something eqivalent to this:
(pairwise key1 value1 key2 value2)
Which would expand to this, m being another macro I've defined (hence I can't simply use a variadic style function):
(list (cons key1 (m value1)) (cons key2 (m value2)))
I've tried this:
(define-syntax pairwise
(syntax-rules ()
((_ key value ...)
(list (cons key (m value)) ...))))
But as I guessed it expanded to:
(list (cons key1 (m value1)) (cons key1 (m key2)) (cons key1 (m value2)))
I'm a bit stuck on how to process these elements pairwise in the way I'd like, without requiring a user to add inner brackets.

You can do this with recursion. Instead of having one case that looks like
((_ key value ...)
(list (cons key (m value)) ...))
You can have two cases that look like
((_)
'())
((_ key value . rest)
(cons (cons key (m value)) (pairwise . rest)))
Similar to how you would design a recursive list-processing function, but with the base case as a syntax-rules case (detected at compile-time) instead of an if or cond condition (detected at run-time).

Related

In Lisp, can you construct a `check-type` that throws an error if the value is not a hash-table with all integer keys and values?

Say I have a function:
(defun distribution-to-list (distribution)
(check-type distribution hash-table)
(loop for key being each hash-key of distribution
using (hash-value value) nconc (loop repeat value collect key)))
I want to ensure that at least all the values of the hash-table that are passed in are integers, as I'm using them to repeat values into a big list. Is there any way to do so with check-type before the inner loop? Or would it be good enough practice to let the inner loop macro throw a type error when it tries to repeat a string? (or whatever non integer type)
If you can write a function that can check whether a value is acceptable, then you can use satisfies to construct a type specifier, such as (satisfies is-acceptable). E.g.,
(defun all-integer-keys-p (ht)
(loop for k being each hash-key in ht
always (integerp k)))
(let ((h (make-hash-table)))
;; when the table contains only integer
;; keys, we're fine
(setf (gethash 1 h) 'foo
(gethash 2 h) 'bar)
(check-type h (satisfies all-integer-keys-p))
;; but a non-integer key will lead to an
;; error from CHECK-TYPE
(setf (gethash 'three h) 'baz)
(check-type h (satisfies all-integer-keys-p)))
With deftype, you can define a type as shorthand for (satisfies all-integer-keys-p), which you may find more readable:
(deftype all-integer-key-hash-table ()
`(satisfies all-integer-keys-p))
(let ((h (make-hash-table)))
(setf (gethash 1 h) 'foo
(gethash 2 h) 'bar)
(check-type h all-integer-key-hash-table)
(setf (gethash 'three h) 'baz)
(check-type h all-integer-key-hash-table))

hash-tables, counting duplicate keys, scheme

I'm hoping someone can help me with this while I continue searching for a solution.
I'm confused on how to iterate through a hash table and find duplicate keys. I want to remove the duplicates, but consolidate their values.
So, say I have a list of strings:
(define strings '("abcde" "bcdea" "cdeab" "deabc" "eabcd" "abcde"))
And I store them into a hash table where the values are their index positions in the list.
So, I'm wanting to build a hash table like this:
(abcde (0, 5))
(bcdea 1)
(cdeab 2)
(deabc 3)
(eabcd 4)
Each string is a key, and the value is a list of the indexes where that string is found. Basically, I'm counting the number of occurrences of a substring in a large string, and noting their positions.
I know how to make the hash table:
(define my-hash-table (make-hash))
(for-each (lambda (s v) (hash-set! my-hash-table s v)) strings values) ;;values is a list of 0,1,2,3,4,5
(map (lambda (s) (list s (hash-ref my-hash-table s))) strings)
This just builds a hash table of the keys and their values, it doesn't consider if a key is already present in the table.
I'd appreciate any advice. If someone doesn't mind going through it step-by-step with me I'd be very grateful, I'm trying to learn scheme.
I'm using RSR5.
The trick is to check whether each key has already a value, if so we append it to a list - by definition, each key can only have one value associated. I think you're looking for something like this:
(define strings '("abcde" "bcdea" "cdeab" "deabc" "eabcd" "abcde"))
(define values '(0 1 2 3 4 5))
(define my-hash-table (make-hash))
(for-each (lambda (s v)
(hash-update! my-hash-table
s
(lambda (a) (cons v a)) ; add element to list
(lambda () '()))) ; we start with '()
strings
values)
Alternatively, we can create and update the hash table using a functional style of programming:
(define my-hash-table
(foldl (lambda (s v a)
(hash-update a
s
(lambda (a) (cons v a)) ; add element to list
(lambda () '()))) ; we start with '()
(hash)
strings
values))
Either way, it works as expected:
(hash->list my-hash-table) ; we get a keys/values list for free
=> '(("eabcd" 4) ("deabc" 3) ("bcdea" 1) ("cdeab" 2) ("abcde" 5 0))
Are you using SRFI 69? Look into hash-table-update!.

Creating a function to return a core expression using macros

I've been working on some code using R5RS for an assignment to expand certain expressions into core forms of the expression using macros. These are put through a provided eval/apply loop later
(define expand (lambda (exp)
(letrec-syntax
((let (syntax-rules ()
((_ ((var init) ...) body ...)
(`((lambda (var ...) body ...) init ...))))) )
(exp)) ; sequence to expand
))
(expand (let ((x 2) (y 1)) (+ x y)) )
When I run the code like this I get back ;The object 3 is not applicable. but so it looks like it's actually evaluating exp, but I need to get back a uh...string representation.
If I embed the expression I want expanded into the letrec-syntax body I get back what I actually want. Like so:
(define expand (lambda (exp)
(letrec-syntax
((let (syntax-rules ()
((_ ((var init) ...) body ...)
(`((lambda (var ...) body ...) init ...))))) )
(let ((x 2) (y 1)) (+ x y))) ; sequence to expand
))
I get back ...
;The object ((lambda (x y) (+ x y)) 2 1) is not applicable Which looks like what I want to send back to be interpreted.
So my question is how can I rewrite this to take any exp given to expand like in the first example, but return its expanded form like in the second example?
I think the problem has something to do with exp defined by lambda being in the wrong scope in regards to letrec-syntax. I'm very new to Scheme, and I feel like I'm missing a simple solution here. My best leads so far involve using syntax-case somehow or something about hygienics, but I feel like I've been chasing my tail trying to research those topics so far and I'm not sure they're the right direction.
Thanks for any assistance. :)
This works:
(define-syntax expand
(syntax-rules (let)
((_ (let ((var init) ...) body ...))
'((lambda (var ...) body ...) init ...))))
then
> (expand (let ((x 2) (y 1)) (+ x y)))
((lambda (x y) (+ x y)) 2 1)

Racket / Scheme - Syntax-Case

I'm currently working on an assigment about racket macros. In one of the questions we`re asked to define a macro my-set! which acts like this:
(define x 3)
(define y 5)
(define z 7)
(my-set! (x (+ x y)))
(my-set! (x (+ x y)) (z 6))
x
13
y
5
z
6
I found this interesting document on syntax-case http://www.cs.indiana.edu/~dyb/pubs/tr356.pdf
Currently my macro works but i'm trying to add a "fender" like on page 10 of the document to fend off errors like if one of the variables arent identifiers or anything else.
Here`s my code:
(define-syntax my-set!
(letrec ((all-ids?
(λ (ls)
(or (null? ls)
(and (identifier? (car ls))
(all-ids? (cdr ls)))))))
(lambda (x)
(syntax-case x ()
((_ (var val) (var2 val2) (var3 val3) ...)
(all-ids? (syntax (var var2 var3 ...)))
(syntax (begin (set! var val) (my-set! (var2 val2) (var3 val3) ...))))
((_ (var val))
(syntax (set! var val)))))))
If I test this exact code without the fender, it works perfectly. But when I run this:
(define a 1)
(define b 1)
(define c 1)
(my-set! (a 3) (b 4) (c 5))
I get this:
car: contract violation expected: pair?
given: syntax:C:\Users\mgiroux\Desktop\define-myset.rkt:40:26 (a b c)
Seems like all-ids? cant (car) of (a b c) cause its not a list? I tried passing it as a list but didnt work either, i seem to have copied exactly the way they do it in the pdf I linked.. What am I missing here?
#'(var var2 var3 ...) is indeed not a list. It's a syntax object that wraps a list. You should use syntax->list to extract out the items into a list, thus your guard should look like:
(all-ids? (syntax->list #'(var var2 var3 ...)))

How to map a macro over a list - or - How to use macros to define data types

I like to build a REPL with my own datatypes, but I don't like to write all the same pattern functions over and over again.
So this is a nut, which bothers me.
I got my own set of primitive datatypes (define primitives '("mytrue" "myfalse" "mynumber" ...))
Also I have (define primitiveTesters (list "mytrue?" "myfalse?" "mynumber?" ... )
The problem now is, I just want to apply (map) or a macro to get the datatype? procedurces, which basically just checks if the car of record (mynumber . ( . )) exists.
So something similar like (mynumber? (car (mynumber.(1.))) => #t in the end. But for this I need (define mynumber? (lambda (...)(...))
My define-batching macro looks like this, but I just have no luck to infuse the <variable>.
(define-syntax define-batching
(syntax-rules ()
((_ value expr)(define value expr))
((_ value) value)
((_ value1 value2 ...) (begin (define value1 expr) (define-batching test2...)))
))
So have I reached a dead end of scheme ?
I've seen something similar, I think in Emacs Lisp.
What I am looking for in the end is:
(define checker '(audi? volkswagen? mercedes?))
(define datatype '(audi volkswagen mercedes))
(map define-checker checker datatype )
or
(define-checker (car checker) (car datatype))
If I understood the question right, you need a macro
to define your own type checkers?
Here is one way to do it:
(define-syntax define-checker
(syntax-rules ()
[(define-checker name tag)
(define (name object)
(and (list? object)
(not (null? object))
(eq? (car object) 'tag)))]))
(define-checker my-car? car)
(my-car? '(car audi black)) ; evaluates to #t
(my-car? '(truck ford pink)) ; evaluates to #f
Addendum:
If you write
(define checker '(audi? volkswagen? mercedes?))
(define datatype '(audi volkswagen mercedes))
the values will become available at runtime.
Therefore you need to a different approach.
You could for example write:
(define-checker+datatype (audi? audi) (volkswagen? volkswagen?))
Here is the code:
(define-syntax define-checker
(syntax-rules ()
[(define-checker name tag)
(define (name object)
(and (list? object)
(not (null? object))
(eq? (car object) 'tag)))]))
(define-syntax define-checkers+datatype
(syntax-rules ()
[(define-checkers+datatype (name tag) ...)
(begin
(define-checker name tag)
...)]))
(define-checkers+datatype (audi? audi) (wv? wv))
(audi? '(audi black))
define-syntax is hygienic, that means it cannot influence on parent environment, that means it cannot define symbols in it.
You may try to use er-, ir- macro-transformers which allow you to explicit renames symbols.
keywords to google in you scheme documentation are 'er-macro-transformet' and 'ir-macro-transformer'