anything
2021-3-21 11:14:22

I’m reading Beautiful Racket. I decided to change the jsonic delimiters @$ … $@ to just ( … ). This raised the difficulty of reading s-exp recursively. Beautiful Racket’s from/to is not sufficient for this. I could perhaps call read directly from the tokenizer as soon as I see "(". But I’d have to somehow put the "(" back in the stream otherwise read would start after the parenthesis.

I also considered leaving that up to the parser. That seems more difficult. It requires me to write macros I don’t know how to write. I built, for instance, this kind of parse-tree. parser-test1.rkt> (parse-to-datum (apply-tokenizer-maker make-tokenizer "(= 2 (+ 1 1))")) '(jsonic-program (jsonic-sexp "(" (jsonic-program (jsonic-char "=") (jsonic-char " ") (jsonic-char "2") (jsonic-char " ") (jsonic-sexp "(" (jsonic-program (jsonic-char "+") (jsonic-char " ") (jsonic-char "1") (jsonic-char " ") (jsonic-char "1")) ")")) ")")) But I don’t know how to write a macro jsonic-sexp that would perhaps concatenate all of its arguments as a final string and then call read and eval on it. All macros are string-producing so jsonic-sexp needs to just handle lots of strings, concatenate them and eval. That’s how I see it right now. I kinda feel that, given the level I am right now, I should handle this with a trick or two in the tokenizer. For instance, I could perhaps write a recursive procedure that reads the port until it finds the complete s-exp, producing a single token with the entire s-exp in there. (I also don’t really know how to do this right now, but I think I could somehow pull it off. I mean, I don’t know because the "(" has already been read out of the port.)


sorawee
2021-3-21 11:23:44

If your port is a file-stream port or a string port, you can use the following unget function to put ( back:

(define (unget s port) (file-position port (- (file-position port) (string-utf-8-length s))))


sorawee
2021-3-21 11:25:18

E.g.:

(lexer ["(" (begin (unget lexeme input-port) (read input-port))]


anything
2021-3-21 11:42:39

That’s so cool! That’s really the trick I was looking for! Very cool! Thank yu so much! tokenizer.rkt> (apply-tokenizer-maker make-tokenizer "(= 2 (+ 1 1))") '((= 2 (+ 1 1)))


raoul.schorer
2021-3-21 12:03:00

I have a unit defining a struct named packed-vector with #:property prop:sequence . I wanted to make in-packed-vector using define-sequence-syntax and use it with prop:sequence , but unfortunately it seems define-unit: cannot export syntax from a unit in: in-packed-vector . Is there any way to parametrize a module (such as is possible with unit) while still allowing me to do what I want?


raoul.schorer
2021-3-21 12:10:40

samth spoke about “just using a lambda instead of a unit” for parametrization. But I don’t get what he means.


laurent.orseau
2021-3-21 12:29:22

I guess it means you can create a normal module, where all the functions are wrapped in a single lambda that takes the ‘unit parameters’ as arguments and returns all the functions


laurent.orseau
2021-3-21 12:29:57

You can also put all the generated functions in a struct and return the struct for convenience of the caller


laurent.orseau
2021-3-21 12:30:13

(I’m just guessing here, I haven’t done that myself)


raoul.schorer
2021-3-21 12:32:19

Ah, yes! I somehow forgot that Racket allowed returning multiple values! I think that’ll do the trick. Thanks! :+1:


samth
2021-3-21 14:42:15

You can (maybe) put the use of define-sequence-syntax in the unit signature


raoul.schorer
2021-3-21 19:52:41

How can I make a macro where I replace part of an identifier name with an argument value, i.e.: (define-fictive-macro (replace-part-of-id part) (part-whatever #t)) and results would be (replace-part-of-id a) -> (a-whatever #t), (replace-part-of-id b) -> (b-whatever #t) and so on… ?


laurent.orseau
2021-3-21 19:55:28

You can use format-id in a #:with clause of define-simple-macro (or define-syntax-parse-rule if you have the latest version of racket)


laurent.orseau
2021-3-21 19:58:43

Let us know if you get stuck


raoul.schorer
2021-3-21 20:31:29

I have a contract like [u2-vector-set! (-> u2-vector? exact-nonnegative-integer? between-zero-and-max-element any)] . Is there a way to do better than exact-nonnegative-integer? here? Such as, is there some way to tell the contract system: “test that the runtime value is less than the vector length” (of course, I can do that in the implementation but just curious)


sorawee
2021-3-21 20:41:14

Take a look at dependent function contract.



raoul.schorer
2021-3-21 23:13:17

I have a collection of many identifiers such as packed-vector, packed-vector-ref, etc. I would like to make a macro to change those according to an argument, i.e u2-vector, u2-vector-ref, etc. where the argument would be ‘u2’. I understand how to replace an identifier by another, but that would mean I have to provide all the new names as arguments instead of just ‘u2’ in this example. Is there a way to make that easier by replacing only part of the identifier? I’m a bit stuck…


zafar.huma
2021-3-22 02:23:47

@laurent.orseau mentioned format-id above which is what you would want to use to synthesize a new name in your macro. For example, something like: (define-simple-macro (example arg) #:with name (format-id #'arg "~a-vector" (syntax->datum #'arg)) (name #t)) (define (test-vector v) (println v)) (example test); => #t


raoul.schorer
2021-3-22 05:38:00

I got lost in the docs. Indeed, I found the relevant portion now thanks to your example. Sorry about this!