yilin.wei10
2020-8-8 18:41:06

Hi, I have a question about https://docs.racket-lang.org/guide/phases.html?q=phase#%28tech._phase%29 and how macros affect the phase.

Suppose I have the following code where I define the binding to three.

(define three 3) three This works as expected. We can shift the phases by doing, begin-for-syntax - which paraphrasing the documentation means shifting the phase up by one. Wrapping the two statements separately in a begin-for-syntax block works as expected.

If I now define a macro which produces an expr with a define form inside, which phase is the id available in? I had expected that it would be n + 1 of which phase it’s called in but wrapping a three in a begin-for-syntax block and calling expand-arb at the top level gives me an unbound identifier.

(define-syntax (expand-arb stx) (syntax-parse stx [(_) #'(define three 3)]))


soegaard2
2020-8-8 18:45:36

Consider this: #lang racket (require (for-syntax syntax/parse)) (begin-for-syntax (define three 3)) (define-syntax (expand-arb stx) (syntax-parse stx [(_ my-three) (displayln (list three)) ; you can refer to three directly here (with-syntax ([three three]) ; use with-syntax if you need to #'(define my-three three))])) ; refer to three in templates (expand-arb x) x


yilin.wei10
2020-8-8 18:49:10

Hmm OK; what you’re saying is that the define statement doesn’t take a symbol but also the phase information hence the x in this case is x in phase 0?


yilin.wei10
2020-8-8 18:49:58

But what if I introduce a new id in the macro?


soegaard2
2020-8-8 18:51:12

I am saying that (begin-for-syntax (define three 3)) defines three at phase 1. But a phase 1 identifier isn’t automatically a pattern variable.


soegaard2
2020-8-8 18:51:45

That is expanding to, say, #'(begin three) won’t work.


yilin.wei10
2020-8-8 18:52:28

Ah, but I’m simply trying to do (begin-for-syntax three)


yilin.wei10
2020-8-8 18:52:44

Which does work with just the define .


yilin.wei10
2020-8-8 18:53:51

(but not with expand-arb , hence the question)


soegaard2
2020-8-8 18:53:59

To use the value to which three is bound, one must introduce a pattern variable: (with-syntax ([three three]) #'(begin three)) Here the pattern variable got the same name as the phase 1 variable.


yilin.wei10
2020-8-8 18:54:25

Sorry let me write out the code explicitly


soegaard2
2020-8-8 18:56:23

Consider this example: #lang racket (require (for-syntax syntax/parse)) (begin-for-syntax (define three 3)) (define-syntax (expand-arb stx) (syntax-parse stx [(_) (displayln (list three)) ; you can refer to three directly here (with-syntax ([three1 three]) ; use with-syntax if you need to #'(define three three1))])) ; refer to three in templates (expand-arb) three


soegaard2
2020-8-8 18:56:41

Here we try to define a phase 0 variable named three.


soegaard2
2020-8-8 18:57:08

However running the example will give an error: “three: unbound identifier”.


soegaard2
2020-8-8 18:58:03

This is because the three introduced by the macro and the three in the user code has different lexical contexts (but it is unrelated to the phase 1 three).


soegaard2
2020-8-8 18:58:55

To fix it we need to give the three in #'(define three three1) the same context as the user three. This is usually done by passing along the identifier.


soegaard2
2020-8-8 18:59:05

(x in the previous example)


soegaard2
2020-8-8 19:00:44

However we can get the context from stx too. #lang racket (require (for-syntax syntax/parse racket/syntax)) (begin-for-syntax (define three 3)) (define-syntax (expand-arb stx) (syntax-parse stx [(_) (displayln (list three)) (with-syntax ([three1 three] [three (format-id stx "three")]) #'(define three three1))])) (expand-arb) three


yilin.wei10
2020-8-8 19:01:27

Ah OK - I had interpreted that everything at the top level shared a lexical context - is that untrue?


soegaard2
2020-8-8 19:02:45

In the example we are the module-level, not the top-level.


yilin.wei10
2020-8-8 19:04:21

Hmm - I am clearly missing some more context. I will dig in further in the racket reference. Thank you for the explanation!


soegaard2
2020-8-8 19:06:38

The tricky part is that #lang racket ... expands to a module. So it is easy to forget (I have done that in past).

The definition of top-level and module-level is here: https://docs.racket-lang.org/reference/syntax-model.html?q=fully#%28part._fully-expanded%29


gknauth
2020-8-8 19:07:55

Every time I upgrade Racket, say from version 7.7.x.y to 7.8, I always have the same problem with my local packages, namely: ../../../../Applications/Racket/Racket-v7.8/collects/racket/require-transform.rkt:269:2: standard-module-name-resolver: collection not found for module path: format-ymd collection: "format-ymd" in collection directories: /Users/gknauth/Library/Racket/7.8/collects /Applications/Racket/Racket-v7.8/collects ... [175 additional linked and package directories] no package suggestions are available . I can never remember the magic incantation / combination of raco commands that will get me back to normal. Can someone remind me? Thanks. Maybe my setup is unusual because I keep multiple different versions of Racket under /Applications/Racket/.


yilin.wei10
2020-8-8 19:08:28

Hmm, just to clarify, the snippet:

#lang racket (define x 1) (define y x) both are bound in the module level context - but both share the same lexical context correct?


soegaard2
2020-8-8 19:09:12

I usually just install the missing packages one at a time, like: raco pkg install format-ymd

Is there something better?


yilin.wei10
2020-8-8 19:09:23

And if I am interpreting correctly, you’re saying it’s not because they are both module level + phase level that they share the same context, but some other reason?


gknauth
2020-8-8 19:09:48

% raco pkg install format-ymd Resolving "format-ymd" via <https://download.racket-lang.org/releases/7.8/catalog/> Resolving "format-ymd" via <https://pkgs.racket-lang.org> Resolving "format-ymd" via <https://planet-compats.racket-lang.org> raco pkg install: cannot find package on catalogs package: format-ymd


soegaard2
2020-8-8 19:10:14

Yes, they have the same context. They are in the same module, and neither are introduced by a macro.


gknauth
2020-8-8 19:10:18

I’m literally in the directory/folder with the source for format-ymd.


yilin.wei10
2020-8-8 19:11:16

Ah OK - then is the explanation simply, macros like functions introduce their own lexical context?


soegaard2
2020-8-8 19:11:54

Oh. That was bad example. That must mean that the collection format-ymd is in some other multi collection package (not named format-ymd).


gknauth
2020-8-8 19:12:42

% locate format-ymd /Users/gknauth/github/format-ymd


soegaard2
2020-8-8 19:13:06

Ah! You are not downloading format-ymd.

Then you probably need to use raco link


gknauth
2020-8-8 19:13:26

I see. I’ll look into that, thanks.


soegaard2
2020-8-8 19:16:54

@gknauth I have all my Racket source in a folder named GitHub so with the old version of racket I can write: raco link -l | grep GitHub

and get a list of all the old links.


soegaard2
2020-8-8 19:17:42

Yes. Identifiers introduced by macros have a new lexical context.


soegaard2
2020-8-8 19:18:42

Unless one explicitly does something to keep the context from the input.


gknauth
2020-8-8 19:20:10

% raco link -l \| grep github root path: "/Users/gknauth/github" % ls bergy-bits/ itty-bitty/ machine-setup/ pilot-currency/ experiments/ javapjar/ money-matters/ tasks-currency/ format-numbers/ jdkjar/ personal-ledger/ thumbs/ format-ymd/ location-weather/ personal-ledger.tgz weather-bufr/ What more do I have to do, did I do something wrong, do I have to do something differently? I used raco link -d to make the github directory a root. I don’t know if that was enough, if I should have done more.


soegaard2
2020-8-8 19:20:28

You can check the beginning of: https://www.youtube.com/watch?v=Or_yKiI3Ha4


gknauth
2020-8-8 19:20:59

By the way @soegaard2, some of that format-numbers stuff originated with you, I remember you had a way to print real numbers that was sane, and I used it.


soegaard2
2020-8-8 19:21:57

Funny - can’t remember that.


gknauth
2020-8-8 19:22:53

from 2007–2009: ;; real-&gt;scientific-string ;; 2007-04-15 thanks to <mailto:jensaxel@soegaard.net\|jensaxel@soegaard.net> ;; 2009-12-14 modified by gknauth (define real-&gt;scientific-string (case-lambda [(x) (real-&gt;scientific-string x 2)] [(x digits-after-decimal-k) (let* ([sign (if (negative? x) -1 +1)] [x (* sign (inexact-&gt;exact x))] [e-safe (if (= x 0) 0 (floor (/ (log x) (log 10))))] [e-orig (inexact-&gt;exact e-safe)] [e (inexact-&gt;exact (- e-safe))] [x-normalized (* (inexact-&gt;exact x) (expt 10 e))]) (format "~a~ae~a" (if (negative? sign) "-" "") (if (zero? digits-after-decimal-k) (round x-normalized) (real-&gt;decimal-string (exact-&gt;inexact x-normalized) digits-after-decimal-k)) e-orig))])) ;; original format-float came from from Joe Marshall &lt;jmarshall@alum.mit.edu&gt; ;; most of the meat is now in format-numerals


soegaard2
2020-8-8 19:23:04

I think I use: cd github raco link bergy-bits raco link itty-bitty ... But raco link * will probably also work.


gknauth
2020-8-8 19:29:58

Thanks, I got my webapp to run again. raco setup still gave me errors for unrelated things, for example: raco setup: error: during building docs for /Users/gknauth/github/weather-bufr/scribblings/weather-bufr.scrbl raco setup: standard-module-name-resolver: collection not found raco setup: for module path: binaryio raco setup: collection: "binaryio" raco setup: in collection directories: raco setup: /Users/gknauth/Library/Racket/7.8/collects raco setup: /usr/local/racket/latest/collects raco setup: ... [176 additional linked and package directories] but that didn’t stop me from building/running the webapp I was working on.


soegaard2
2020-8-8 19:32:17

Makes sense (if binaryio is only used to build the docs).


gknauth
2020-8-8 19:47:52

binaryio is used in that weather-bufr program itself, but I’ll figure that out later. The main thing is I got my tasks-currency webapp to work again. There are so many things I have to keep track off, take this medication, change these batteries, backup that machine, sync these folders/machines, make a regular phone call, check that radio, renew that contract, renew a certification, update an airplane’s GPS navigation database, etc., that I put it all in a database, and I put the parameters in a config file. E.g., do this daily, if done <= 24 hours ago, green, 24–36 hours yellow, beyond 36 hours, red. Every task item has different thresholds in terms of hours, days, weeks, months, … I try to keep the “task board” all-green, but if things slip into a yellow state, I know I need to do something soon, and if it slips into a red state, I have to do it immediately. All this stuff normally goes into a Calendar type application, and I do that too, but this dashboard approach goes beyond that and shows me the state of all the important things I’ve forgotten (or remembered) to do. Some of these things are to solve “sneaky” problems. The local water bill comes quarterly (Jan Apr Jul Oct) and is due or else. I’ve gotten shutoff notices and late charges in past years when that was the first notice I got. I marched down to the office and complained I never got the bill. (“Oh we did send it to you!” “Well I never got it!“) That was the origin of this particular app. I wanted to make sure I never had to go down to the water office to have those people berate me unfairly. So now it’s all tracked in my database, I know to check their website for the amount due and send it to them well ahead of their deadline. I did that this month, and I’m glad I did, because the July bill never came in the mail, but I was prepared, I beat them at their own game.


soegaard2
2020-8-8 19:53:14

It’s great to have reminders for the periodical tasks. In Denmark most companies use a service where the consumer, can pay periodical bills automatically. It works surprisingly well.

Still need manually to report how much “heating” have been used (I have central heating).


soegaard2
2020-8-8 19:54:19

The “task board” sounds like a great idea.


notjack
2020-8-8 20:13:44

the magic incantation is raco pkg migrate 7.7, I think


notjack
2020-8-8 20:14:03

that will move everything you had installed in 7.7 into your current version


gknauth
2020-8-8 20:14:56

Thank you @notjack!


gknauth
2020-8-8 20:26:08

I probably got the idea from work or from Civil Air Patrol. In CAP we have a status board showing the aircraft in the Wing (US state), where they are, whether they are FMC / PMC / NMC (Full/Partially/Not) Mission Capable, how close they are to 100hr inspections, etc. At work (AccuWeather) we have a zillion status boards for all the services we run, when certain things go red the NOC (network operations center) calls me or one of my colleagues to fix problems immediately, so we like things to stay green (not broken) so we can sleep at night. There are also county/region alert areas for each country, e.g., it’s hot in Denmark as you probably already know, so this is the MeteoAlarm map for Denmark, and we have to monitor that the alerts we send to mobile devices precisely match the info coming from each country’s weather services. http://meteoalarm.eu/en_UK/0/0/DK-Denmark.html


soegaard2
2020-8-8 20:30:21

Yeah - we have a heat wave at the moment. Just in time for schools to start…