josh
2021-1-3 14:41:22

@josh has joined the channel


soegaard2
2021-1-3 15:56:28

An updated version of draft 2. Mostly fixes to grammar and spelling.


gknauth
2021-1-3 16:00:45

Thank you @popa.bogdanp and Happy New Year. I love to see Racket reaching people in new ways.


gknauth
2021-1-3 16:02:38

And Remember is very easy to use. I just have to remember to put in a time for Remember to remind me what I didn’t want to forget.


greg
2021-1-3 17:29:36

@laurent.orseau Typed Racket docs do this a lot.



greg
2021-1-3 17:31:00

Then to use them, use @ and pipes, e.g. @\|define-id\|



greg
2021-1-3 17:37:23

[Lately I’ve been working on something like racket/trace, but emitting structured logging events, and with a lot of srcloc for showing logging “in situ”, almost like a “step logger”.]


greg
2021-1-3 17:50:12

[It’s taking me awhile because I keep pausing to reflect on it, and think about what problem(s) I’m really trying to solve. Like, for example, tracing shows call depth. But, it’s nice if plain old non-tracing logging messages could inherit that call depth (be indented to match the dynamic extent of any traced calls).]


greg
2021-1-3 17:50:58

[End long digression that should instead someday be a blog post. :smile:]


samth
2021-1-3 18:45:41

soegaard2
2021-1-3 18:51:34

From Reddit. Is this a thing, or is he just using an old version?


me1890
2021-1-3 18:57:38

Does it just read for the wrong line endings?


soegaard2
2021-1-3 18:59:07

I think he is referring to the readline library in the repl. https://en.wikipedia.org/wiki/GNU_Readline


me1890
2021-1-3 18:59:13

also, why do they think racket’s end near just now after 25 years :laughing:


me1890
2021-1-3 18:59:47

it’s an old language, it’s not going anywhere


greg
2021-1-3 19:12:29

This is probably a hand-wavy and open-ended question. Maybe instead of an answer, maybe it needs to be changed into one or more better questions. But:

Is there any example or even just research about ways to make it easier to “compose” or “advise” various flavors of define? (Or research why that’s impossible or at least impractically difficult?)

As an example, let’s say I want to write a define-x macro. Either it contributes something extra (say a call to chaperone-procedure) then expands to lambda from racket/base, or, it completely defers and expands to define from racket/base. As a result, it works fine as a drop-in replacement for define from racket/base. But therein is the problem. It expands to define and lambda from racket/base. How do I make it work with a whole “zoo” of defines and lambdas — define from typed/racket/base, define/private and friends from racket/class, define/contract, and on and on.

AFAIK I need to handle these one by one, with bespoke surface replacements for each. That’s tedious. Worse it’s “closed”, not open to working with a define- or lambda-enhancer from from some unknown and/or future third party library. Or vice versa.

Is there a way for various “enhancers” or “advice” to cooperate safely and automatically? Why can’t we all just get along? :smile:


me1890
2021-1-3 19:16:15

Your problem remind’s me a bit of one of python’s problems. People wanted to modify function definitons so they made this pattern: def foo(): return 4 foo = modifier(foo) then to make it nicer, python added the syntax @modifier def foo(): return 4 which is equivalent, but then there was another problem


soegaard2
2021-1-3 19:18:30

Maybe, I am not sure, my experiments with a “binding clause transformer” is relevant. I defined an alternative bind to let that can be extended by the user. The corresponding define operations is called def.

Look in the examples folder to see what’s possible.

See https://github.com/soegaard/bind


me1890
2021-1-3 19:18:41

these didn’t compose, so they added another feature later so that you could ad multiple of these decorators like so: @modifier1 @modifier2 def foo(): return 4 would be equivalent to def foo(): return 4 foo = modifier1(modifier2(foo))


me1890
2021-1-3 19:19:44

perhaps a similar solution is possible in racket


sorawee
2021-1-3 19:23:39

My random thought:

If you create a #lang, you can theoretically make #%module-begin simulates the macro expander itself. E.g., https://lexi-lambda.github.io/blog/2018/09/13/custom-core-forms-in-racket-part-ii-generalizing-to-arbitrary-expressions-and-internal-definitions/

With this, you can partially expand to find define-values and replace them with your define.


greg
2021-1-3 19:26:13

@soegaard2 Thanks I’ll take a look.


greg
2021-1-3 19:27:10

@me1890 Python generators is a good thing for me to look at. IIUC there are an “advice” system but I’m fuzzy on the details.


me1890
2021-1-3 19:27:58

generators or decorators?


greg
2021-1-3 19:28:38

Derp. Yes I meant to type decorators. :smile:


greg
2021-1-3 19:28:57

I don’t know much about them, but I know the difference from generators. :slightly_smiling_face:


me1890
2021-1-3 19:29:38

decorators are a very nice metaprogramming system that allows you to do some very powerful stuff in python


greg
2021-1-3 19:29:40

@sorawee Yes, I think when making a full #lang, all things are possible. What I’m thinking of is “mere” libraries, each of which has an interesting way of enhancing define or lambda. This one can wrap a value in a contract. This one can add some tracing. This one can automatically define some documentation. This one can accept annotations for a type-checker.


greg
2021-1-3 19:30:45

It seems like there should be a story for how these can cooperate, so a user can mix them as desired. Without needing to make a full #lang? Or, at least, a waaaaay easier one-line way of declaring such a lang.


sorawee
2021-1-3 19:32:54

Similar to how we can customize #%app, perhaps there should be #%lambda and #%define-values?


me1890
2021-1-3 19:34:44

would this kind of thing be able to abstract the 6 different kinds of lets in basic scheme?


sorawee
2021-1-3 19:34:46

Just curious, what thread is this?



greg
2021-1-3 19:38:51

@me1890 To be honest I don’t understand my own question well enough, yet, to know how much it is about define and how much it is about lambda. The examples I have in mind are mostly about definitions where the rhs is a lambda. But those are motivating examples, for me, not necessarily the right or complete examples. In few words, I am trying to avoid thinking about all the flavors of let, for now.


greg
2021-1-3 19:42:15

@sorawee I guess like #%app. But IME that’s usually about replacing the one #%app from racket/base with another, singular app. Whereas I think the characteristic I’m thinking of here is more like decorators or advice — a chain of wrappers, each of which gets a shot at adding something then passing along to the next one.


greg
2021-1-3 19:43:15

Maybe they need to be like Racket chaperones (“immutable”) not impersonators if I understand that distinction right.


greg
2021-1-3 19:43:55

They “need to not step on each other’s toes”, is I think the formal academic jargon. :slightly_smiling_face:


soegaard2
2021-1-3 19:44:29

The downside of a, say #%binding-clause or #%lambda supported by define , let and friends is that the expansion pass becomes slower.


me1890
2021-1-3 19:45:06

don’t they all become one form of binding in the end? (one extra step wouldn’t be too bad)


greg
2021-1-3 19:45:30

Probably apples and oranges, different problems, but: racket/match supplies a way for multiple things to contribute match expanders. Something like that for define and/or lambda. waves hands


me1890
2021-1-3 19:47:11

I like the match expander system too, it’s pretty easy to wrap your head around and makes it seem easy enough to write every pattern in terms of app


soegaard2
2021-1-3 19:51:43

That’s more or less the idea behind the forms defined in bind. As a quick example, here is how to expand bind def, lambda etc with a binding clause for delayed expressions. If a variable x is bound to such a delayed expression, it is automatically forced: ; Semantics: ; The binding clause ; [id :delay e] ; will bind id to the result of evaluting the expression (delay e). ; In the body of bind the following bindings are in place: ; reference: id returns (force id) ; assignment: (set! id f) as normal ; application (id arg ...) returns ((force id) arg ...) ; Examples: ; > (bind ([x :delay (/ 1 0)]) 3) ; 3 ; > (bind ([x :delay 3]) (+ x x)) ; 6 ; > (bind ([x :delay (/ 1 0)]) (set! x 4) (+ x x)) ; 8 (define-binding-clause-transformer (:delay stx) (syntax-parse stx [(id:id _ expr) (values (list #`[(id1) #,(syntax/loc stx (delay expr))]) (list #`[id (make-transformer #:context so #:literals (set!) [(set! i e) (syntax/loc so (set! id1 e))] [(i . more) (syntax/loc so (#%app (force id1) . more))] [i:identifier (syntax/loc so (force id1))])]))])) Defining the binding clause transformer makes :delay available everywhere.


greg
2021-1-3 20:04:26

@samth Something like Javascript console groups is something I’ve wanted a long time. And yes I came across tokio-rs/tracing last week while researching, and it has “spans”. ATM I have a with-more-logging-depth form that increases a “depth” continuation mark value. Which is also adjusted by the function tracing forms, but you don’t need to use those. Originally I was stuffing extra logging info into the data member of the logger event vector. But the default log-x forms, as well as those defined by define-logger, put (current-continuation-marks) in that slot. So now I just add continuation marks, and you can use the normal logging forms. If a log receiver knows to retrieve them, it can use them for better presentation (e.g. indent depths and/or allow folding them like groups). At the same time other log receivers don’t get broken.


greg
2021-1-3 20:08:18

TL:DR (log-info "hi") ;depth 0 (with-more-logging-depth (log-info "there")) ;depth 1 (with-more-logging-depth (unaware-code-that-uses-logging-forms)) ;depth 1 (or more) (trace-define (f x) (log-info "hi") ;automatically depth 1 (with-more-logging-depth (log-info "deeper")) ;depth 2 (+ x 2))


greg
2021-1-3 20:10:10

There’s also a with-more-logging-info form that records the time, current-thread, vector-set-performance-stats! eagerly, since log receiver too late to do that.


greg
2021-1-3 20:10:32

etc. etc. Will try to open the alpha repo, soon-ish.


greg
2021-1-3 20:12:57

@soegaard2 That’s really interesting. I got side-tracked by chat here, but will find some time to focus on that. Thanks!


pihentagy
2021-1-3 21:09:35

#lang typed/racket I tried to add typing to the soup, but failed at the first exercise in Advent of Code 2020.

I happened to use the apply function to do the summing.

But apply http://pasterack.org/pastes/60689 fails.


me1890
2021-1-3 21:15:58

you have to do (apply + '(1 2 3))


hazel
2021-1-3 21:33:20

you can just do (+ 1 2 3) in this case. the idea is that: (func arg1 arg2 ... argn) is the same as (apply func (list arg1 arg2 ... argn))


samdphillips
2021-1-3 22:10:41

I feel like I’ve seen that comment on other Racket posts.


ryanc
2021-1-3 22:40:51

@greg The example with define and lambda is one that I remember debating in grad school, and it’s probably older than that. I created “syntax functors” to explore one style of solution. Git repo here: https://github.com/rmculpepper/racket-functor/, not a package yet but maybe soon.


rokitna
2021-1-3 22:50:31

If you just want it to be able to expand to a different define form, you can have a syntax where the define form to expand to is one of the arguments (possibly accompanied by some arguments to pass through to it). For instance…

  (<= 0 n))

Then when you have multiple hints to add, you can stack them:

  (<= 0 n))

In this case, it may make sense to promote the function signature to the front again so it doesn’t get lost, and one way to do that is with another helper macro:

  (defining-with-y (defining-with-x (define)))
  (<= 0 n))

This approach is very syntactic, and it may not be the best if you want your different define variants to have unpredictable differences in the grammars they expect or the places they’re called in. For instance, define* from the define-match-spread-out library allows a definition to be written in multiple top-level cases, and this approach would need to be modified to accommodate that.

This approach is also not likely to be great at reporting errors if all these macros do is expand into the given macro and hope that it works. To improve upon that, I think the grammar of a hintable define variant should take some kind of “report errors this way” argument. Perhaps this would involve writing a define/derived in a similar spirit to struct/derived and match/derived.

Finally, it also doesn’t give you a concurrent way to specify multiple hints “at once.” The hints are always in an ordered stack. Because of this, if you want to make one hint complain if another hint hasn’t been used, or if you want to make two hints that are mutually exclusive, you might need a more sophisticated approach. The more sophisticated approach might resemble designing a multiple-inheritance object system (e.g. mixins). At any rate, there may be some serious compile-time abstraction involved, representing a define hint’s compile-time interface as some kind of encapsulated compile-time object rather than as an s-expression.


jestarray
2021-1-3 23:56:59

i didn’t know typed racket inspired typescript according to that video


jestarray
2021-1-3 23:59:54

he argues for other languages which i have some problems with: lua is much slower than racket and much worse… js requires you to pull the entire v8 engine in, not to mention brendan eich said the best parts of javascript are because of scheme/lisp and ruby i have not tried..


jestarray
2021-1-4 00:05:02

i think racket hits a very good spot for a scripting language, my main complaints are sometimes lacking libraries, some things like map not passing the index(minor), but mailny the IDE experience is eh… drracket is slow and clunky and doesnt keep undo-redo history well…. and vscode extensions dont do much . It’d be nice if we could have inline hints like what the rust-analyzer extension does for rust


notjack
2021-1-4 05:53:29

Lots of good thoughts here so far, and several interesting examples of use cases for this. My two cents is that “python decorators, but at compile time” is something that I badly want #lang racket to ship with out of the box.


sorawee
2021-1-4 07:31:44

Turns out he really is talking about the default mode of read-line as @me1890 mentioned above. The doc states explicitly that:

> Thus, when a file is opened in text mode, ’linefeed is usually the appropriate read-line mode. So do you know why 'any is required to be cross-platform?


me1890
2021-1-4 07:52:12

lol


me1890
2021-1-4 07:53:04

this mans really complaining about having to type ’return-linefeed


sorawee
2021-1-4 07:57:21

> map not passing the index, Operations on lists based on index take linear time, so map not passing the index is the right decision IMO.

Plus, if you really want an index for some reason, you can always use for/list:

(for/list ([x (in-list xs)] [i (in-naturals)]) (list x i))


sorawee
2021-1-4 07:57:39

You can also use in-indexed, though I prefer using in-naturals more