comer
2020-4-21 07:03:19

@comer has joined the channel


popa.bogdanp
2020-4-21 07:29:58

What’s the right way for a language to generate code such that the bindings it references for core constructs are in a separate context from the bindings that user code can introduce? For example, in a custom language I have the following code to compile anonymous functions:

[(keyword 'fun) (skip l 'lparen) (with-syntax ([(arg ...) (parse-ident-list l)] [(e ...) (parse-body l)]) (syntax/loc (token->syntax t) (lambda (arg ...) e ...)))] so code in my language like

let f = fun(x) x end compiles to

(define f (lambda (x) x)) which works great until the user writes something like

let lambda = 1 let f = fun(x) x end at which point the lambda in the compiled code will refer to the binding that the user introduced, which isn’t what I want. I’ve looked through the custom languages under racket/* on GitHub, but I haven’t seen any that solve this particular problem (or I might have missed it if they did). I noticed datalog does something with make-syntax-introducer, but I’m not sure how I can create an introducer that is able to reference the module language of the resulting module.


soegaard2
2020-4-21 08:50:46

I think you accidentally gave the identifiers a context in the reader. As an experiment, I tried this:


soegaard2
2020-4-21 08:50:51

soegaard2
2020-4-21 08:51:06

Running it gives 42.


soegaard2
2020-4-21 08:53:03

When the macro is applied the identifiers in the input are marked (conceptually at least) by a syntax-introducer - giving the user supplied lambda and the lambda in the macro body different contexts.


soegaard2
2020-4-21 08:54:24

Depending on the details, you might need to do this manually in the reader - but it depends on how your setup is.


popa.bogdanp
2020-4-21 09:02:26

My reader calls strip-context on the generated syntax. My (probably flawed) understanding is that the effect of that is that the expander gets a context-less syntax and then introduces all the appropriate scopes itself, which seems to be what is happening. i.e. the program

let lambda = 1 let f = fun(x) x end expands in the same way that the racket program

(define lambda 1) (define f (lambda (x) 1)) does, which isn’t what I want. The bindings created in the generated program should have a different scope from the bindings referenced by language builtins or keywords.


popa.bogdanp
2020-4-21 09:04:29

What I’m trying to avoid is a user of this language creating a binding called “lambda” at the toplevel and then being confused about why fun no longer works.


soegaard2
2020-4-21 09:05:56

You can use a syntax introducer to give the implemented language a new scope:

(define introduce (make-syntax-introducer 'my-lang-scope))


soegaard2
2020-4-21 09:06:09

Then use (introduce (strip-context ...))


soegaard2
2020-4-21 09:06:12

in the reader.


soegaard2
2020-4-21 09:06:54

(I think)


popa.bogdanp
2020-4-21 09:11:13

It seems like if I do that then

[(keyword 'fun) (skip l 'lparen) (with-syntax ([(arg ...) (parse-ident-list l)] [(e ...) (parse-body l)]) (syntax/loc (token->syntax t) (lambda (arg ...) e ...)))] the lambda here will be placed in the same scope set up by introduce, in which case I think I’d be back to square 1. If I do

#`(#,(datum->syntax #f 'lambda) (arg ...) e ...) instead, then it’d reference the lambda in my reader’s scope (assuming I also drop the strip-context), which might be OK, but still doesn’t feel quite right. The language also has syntax for subscripting collection values

[(lsqbrace) (skip l 'lsqbrace) (define sub-expr (parse-expression l)) (skip l 'rsqbrace) (loop (with-syntax ([e expr] [arg-e sub-expr]) (syntax/loc expr (subscript e arg-e))))] so if I changed this in the same way then subscript would have to be referenced from the reader’s scope, which doesn’t seem right.


popa.bogdanp
2020-4-21 09:12:52

(whereas now subscript is provided by the module language)


popa.bogdanp
2020-4-21 09:14:02

which also doesn’t seem quite right, because subscript should probably not be accessible by user code; so maybe it makes sense after all to have “builtins” be referenced through the reader’s scope


popa.bogdanp
2020-4-21 09:14:30

it seems like that might be roughly what algol60 is doing here:

https://github.com/racket/algol60/blob/master/compile.rkt#L398

though I don’t fully grok that code yet


soegaard2
2020-4-21 09:16:36

Last “what if” :slightly_smiling_face:

What if you export introduce from the reader, and then do this: [(keyword 'fun) (skip l 'lparen) (with-syntax ([(arg ...) (parse-ident-list l)] [(e ...) (parse-body l)]) (introduce (syntax/loc (token->syntax t) (lambda (arg ...) e ...))))]


popa.bogdanp
2020-4-21 09:23:44

I think if I did that, strip-context would just remove it. I’d probably have to replace strip-context with a syntax delta introducer so I can surgically strip just the context of my compiler. I’ll give that a try


popa.bogdanp
2020-4-21 09:52:53

OK, wrapping the module in an introducer and then using it to flip the builtins seems to get rid of the original problem. Now the builtins get referenced through the compiler’s scope, which doesn’t seem that bad and has the advantage that they don’t have to be exposed in the resulting module. Thanks, @soegaard2!


soegaard2
2020-4-21 09:55:44

Great.


samth
2020-4-21 13:02:48

@pavpanchekha also, the original scheme workshop paper is still a pretty good ffi reference


rxg
2020-4-21 15:22:50

@pavpanchekha the Racket nlopt wrapper library has some examples of passing racket functions as C callbacks. However, one observation: it’s better to pass closures to C than to use the typical C clientData kind of interface. Closures “just work”. https://github.com/jkominek/nlopt


arunsk.tec
2020-4-21 19:58:57

@arunsk.tec has joined the channel


chas
2020-4-21 20:51:50

@chas has joined the channel


johnsmithaaa100
2020-4-21 22:23:19

@johnsmithaaa100 has joined the channel


lcsfs11
2020-4-21 22:29:11

@lcsfs11 has joined the channel


lcsfs11
2020-4-21 22:33:14

hello, I’m Lucas, new here. I was wondering, if A is a matrix defined as a list of lists (I’m doing some throwaway code for some abstract algebra homework computations), then (define (transpose A) (apply map list A)) does the right thing. If apply wasn’t intelligent enough to group map and list, would there be a similarly straightforward way of defining this function?


sorawee
2020-4-21 22:42:17

I’m not sure what you meant by “If apply wasn’t intelligent enough to group map and list”


sorawee
2020-4-21 22:42:44

If you use Racket, apply would work the way you expect it to work.


lcsfs11
2020-4-21 22:45:33

I meant, in the hypothetical case that apply could only be called with a function and the arguments, like (apply f lst)


sorawee
2020-4-21 22:46:46

Then (apply map (cons list A))?


sorawee
2020-4-21 22:48:17

(apply f a … xs) is really just a shorthand of (apply f (list* a ... xs)) which is equivalent to (f a ... x ...) where (list x ...) = xs.


lcsfs11
2020-4-21 22:49:10

ah, now I get how apply works


lcsfs11
2020-4-21 23:00:31

my question was whether I could craft a function f , using map and list , in such a way that (apply f '((1 2 3) (4 5 6)) would be '((1 4) (2 5) (3 6)) . It was a puzzle-like question, though, out of curiosity.


deactivateduser60718
2020-4-21 23:01:50

sorawee
2020-4-21 23:02:43

Do you really mean (apply f '((1 2 3) (4 5 6))? Or you actually want (f '((1 2 3) (4 5 6))?


sorawee
2020-4-21 23:03:14

For the latter, that f would be called transpose, and it’s a standard exercise on list manipulation :slightly_smiling_face:


lcsfs11
2020-4-21 23:07:24

I meant the former, I figured (lambda (A) (apply map list A)) does the latter, and you helped me understand why :+1:


deactivateduser60718
2020-4-22 00:36:58

I wrote a require transformer that searches parent directories for an rcfile.

(define-syntax nearest-rc (make-require-transformer (λ (stx) (define dir (syntax-source-directory stx)) (unless (path? dir) (raise-syntax-error 'nearest-u/a "Cannot find search directory. Are you using this macro in a file on disk?")) (define p (find-config/with-cache dir)) (unless (path? p) (error 'nearest-u/a "Cannot find config file when searching from ~a" dir)) (with-syntax ([path (path->string p)]) (expand-import #'path))))) The macro stepper shows that (require (nearest-rc)) expands to something like this. (#%require (just-meta 0 (rename (file "/home/sage/Code/unlike-assets/unlike-assets/unlike-assets/try.rkt") data data)) (only (file "/home/sage/Code/unlike-assets/unlike-assets/unlike-assets/try.rkt"))) data is indeed provided from the try.rkt module that you see in the expansion, but the REPL complains that data is not bound. What do I need to do to the transformer to fix this?


deactivateduser60718
2020-4-22 00:43:36

Ah, I got it.

The syntax object needed some lexical context from stx. The solution seemed to be changing the expand-import as follows. (expand-import (datum->syntax stx `(file ,(path->string p))))


ashleynykiel
2020-4-22 01:03:46

@ashleynykiel has joined the channel


greg
2020-4-22 01:07:33

Sometimes I’m like, “Emacs, go home, you’re drunk because you’ve seen too much over too many decades of computing history”. :simple_smile: https://github.com/greghendershott/racket-mode/issues/450


greg
2020-4-22 01:10:00

OTOH maybe this is what Emacs is telling me.


wlbberman
2020-4-22 01:29:13

Possibly, thank you I’ll take a look


jestarray
2020-4-22 03:18:17

how do i evaluate a .rkt file through CLI?


jestarray
2020-4-22 03:18:31

racket -f <filename> loads it in


jestarray
2020-4-22 03:26:27

trying to debug this error: make-directory: cannot make directory path: C:\Program Files\Racket\share\pkgs\errortrace-lib\errortrace\compiled\drracket\ system error: Permission denied; errno=13 Trying to use pollens select function https://docs.racket-lang.org/pollen/Core.html?q=select#%28def._%28%28lib._pollen%2Fcore..rkt%29._select%29%29 to read a file and grab the date. I tried to call it in multiple ways , (select 'time (build-path (current-directory) "chapter1" "test.html"))