
Updated to included links to talks with live video and code


I want to be able to write:
(my-list
1
(define x 2)
x
3)
and get '(1 2 3)
as a result. Is there an easy way to do this?

Like a macro that transforms to (let ([ x 2 ]) (list 1 x 3))
?

Something like that, though I hope that evaluation order is also preserved. So 1, 2, 3 should be evaluated in order.

I think I want the behavior of #%module-begin
, which can identify expressions and wrap them with print-values
, but leave define-values
/ define-syntaxes
alone.

I guess local-expand
is unavoidable… though I really want to avoid it if possible.

I would like to build “the racket guide” with scribble to produce a pdf with smaller page margins (for printing it myself). Is this easily doable or rather complicated?

@dbriemann Let’s try. First we need to figure out how to build the pdf with default margins.

First we need to fetch the source of the Guide. It’s here: https://github.com/racket/racket/tree/master/pkgs/racket-doc/scribblings/guide

yea i have it already checked out and i already generated some markdown with scribble --markdown *.scrbl
but it generated a lot of files instead of one.. presumably there is some index file

also still trying to install pdflatex here on my work computer

mac?

(md was just a test)

no linux vm. just need to find the right tex packages

Ok - on mac TeXLive is ideal.

It might be a bit large on a vm though.

i installed texlive-base but maybe that is not enough

no it should have space. it’s a local vm so i can work on linux instead of windows :))

it’s not that fast but it has some resources

ok got it.. still installing some packages

Fwiw there is also a TeXLive for Windows.

Can you take the (multiple files) markdown generated and just do: $ cat *.md > full.md
That assumes the md files generated are named in such a way as to sort in the proper order they should exist in the final result.

yea but i am not very well versed in windows.. also all my tools are on my linux vm so i prefer that. i only have a windows system here because my company forces me to have it :slightly_smiling_face:

:slightly_smiling_face:

Yeah, I run TeXLive at work (Win10 machine), when it just has to look nice, especially diagrams.

yea that would work but my guess is that for the —pdf flag this should work differently

chapters are not numbered in file names so it would be painful to append them all

let’s try what happens with scribble --pdf *.scrbl

Guess i am missing some “default” style there: ! LaTeX Error: File `relsize.sty’ not found.

Google says relsize.sty
is in a contrib/relsize

Found this in the documentation of Scribble:

scribble --latex-section 0 file.scrbl
will generate the TeX files. Can’t figure out where the paper size and margins are set though.

Thanks I will try soon. Have a meeting now. Also now running this on my own machine.. feels way better. Also this time I could generate a pdf for lambda.scrbl

I think the trick is to write you own prefix.tex file with a documentclass that has the papersize and margins you want. Then use --prefix
with scribble
. Example prefix files here: https://github.com/racket/scribble/search?q=documentclass&unscoped_q=documentclass

Thanks very much. I will try that after the meeting

Was file.scrbl
just an example file? Or is there some kind of index file for the whole guide?

That was an example. I was running scribble
on a simpler example.

\documentclass[a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[margin=0.5in]{geometry}

ok got it

This prefix.tex
worked on my simpler example.

Yes I tried that on lambda.scrbl and it also works with —pdf . great thanks.

and i guess guide.scrbl is the “main” entry point

Sounds right.

This generally worked and reduced page count from 400 to 241. But there are still some style fails now. Will figure it out!

The prefix.tex
from before was a small modification of scribble-prefix.tex
. Maybe we should try to modify manual-prefix.tex
instead: % This is the prefix for PLT Scheme manuals
\documentclass{article}
\parskip=10pt
\parindent=0pt
\partopsep=0pt
% Adjust margins to match HTML width for
% fixed-width font
\advance \oddsidemargin by -0.15in
\advance \evensidemargin by -0.15in
\advance \textwidth by 0.3in
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

Also just discovered that some kind of links do not work. E.g. on the first page there is If you want an especially quick introduction to Racket, start with §??? "[missing]".
which is If you want an especially quick introduction to Racket, start with @\|Quick\|.
in the code.

Add +m --redirect-main <http://docs.racket-lang.org>
as options.

(I got help to figure that out the other day :slightly_smiling_face: )

nice thanks :slightly_smiling_face: just trying some changes to the prefix.tex

Ah i see now the problem is that the notes on the side use (at least a part of) the margin. Guess I have to experiment a bit

Ok this works \usepackage[left=0.7in,top=0.5in,bottom=0.5in]{geometry}

It’s not beautiful but it saves some money when printing :slightly_smiling_face: Now there is only one optional step left. Is there a way to change the color scheme of code examples to black and white? I would hope this improves readability compared to just printing this in grayscale

You could avoid local-expand
if you syntactically recognize define
and don’t support things that expand to define
. But really you should use local-expand
.

I was discussing the aesthetic elegance of Racket in another slack, using the following zip
example: (define zip (λ args (apply map list args)))
But I have to admit, I like the semantics of returning a result that is as long as the shortest argument (vs. raising an exception), so I coded: (define (my-zip . args)
(let loop ([ lists args ][ acc '() ])
(if (ormap null? lists)
(reverse acc)
(loop (map cdr lists)
(cons (map car lists) acc)))))
While aesthetically pleasing (to me), I don’t like having to allocate a new list due to reverse
- is there a more efficient way to code this?

The idea being: (my-zip '(1 2 3) '(4 5) '(6 7 8 9))
=> '((1 4 6) (2 5 7))

Is there some reason you don’t want to cons
onto the recursive call? (define (my-zip . args)
(let loop ([ lists args ])
(if (ormap null? lists)
null
(cons (map car lists)
(loop (map cdr lists))))))

I usually lean toward an accumulator approach to get optimized tail calls.

I don’t have an intuitive feel for which of these is more efficient actually. I guess I can benchmark them on some large lists.

My guess is that cons
ing onto the recursive call will be about the same same or faster. Either way, there’s a continuation to represent, which is to build the list in the right order after you have all of the pieces. A list to reverse is a fine representation of that continuation. But unlike many language implementations, Racket has a good general-purpose representation of continuations already, so you can rely on it more instead of avoiding it.

Awesome - thanks for the tip! I likely won’t be zipping lists that are ridiculously long anyway.

Sorry, maybe I’m missing something, does (map list . lists)
not work?

It works fine - as long as the lists in lists
have the same length.

@badkins I offer this solution: (define (zip . xss)
(for/list ([firsts (in-values-sequence (apply in-parallel xss))])
firsts))

Or simply: (define (zip . xss)
(sequence->list (in-values-sequence (apply in-parallel xss))))

sometimes i hate scheme (vs. CL)

I benchmarked 4 versions, and it appears my original with the reverse
is the fastest. Second place (~ 1.3x) is @mflatt’s version that just conses the results onto the recursive call. @soegaard2’s came in fairly close together at 2.6x and 2.8x. I’ll post the code in a thread. I ran it a bunch of times while rotating the order of the calls (in case there was a JIT issue) e.g. 1,2,3,4; 2,3,4,1; etc. EDIT: with a large N of 10M and a (collect-garbage)
step before each timing, the version consing the results onto the recursive call is just slightly faster.

#lang racket
(define N 10000000)
(define arg1 (range N))
(define arg2 (reverse arg1))
(define temp (range (/ N 2)))
(define arg3 (append temp (reverse temp)))
(define (my-zip . args)
(let loop ([ lists args ][ acc '() ])
(if (ormap null? lists)
(reverse acc)
(loop (map cdr lists)
(cons (map car lists) acc)))))
(define (my-zip2 . xss)
(for/list ([firsts (in-values-sequence (apply in-parallel xss))])
firsts))
(define (my-zip3 . args)
(let loop ([ lists args ])
(if (ormap null? lists)
null
(cons (map car lists)
(loop (map cdr lists))))))
(define (my-zip4 . xss)
(sequence->list (in-values-sequence (apply in-parallel xss))))
(collect-garbage)
(time (my-zip2 arg1 arg2 arg3) (void))
(collect-garbage)
(time (my-zip3 arg1 arg2 arg3) (void))
(collect-garbage)
(time (my-zip4 arg1 arg2 arg3) (void))
(collect-garbage)
(time (my-zip arg1 arg2 arg3) (void))

Interestingly, when I cranked up N to 10M, the non-tail-recursion version (3) is much closer - more like 1.06x

@mflatt as I mentioned in the other thread, your version is really close which would’ve surprised me prior to our conversation. With a large N of 10M it’s only about 6% slower. It’s nice to be able to choose either one based on reasons other than efficiency.

Is there a difference between BC and CS?

I’m running BC at the moment. Not sure if CS changes anything here.

lol - we both typed that at the same time - my comment in the channel :slightly_smiling_face:

I don’t have a CS yet :disappointed:

I recommend including a (collect-garbage)
call before each time
, just to make sure you’re not counting GC that belongs to a previous test against the next test. It may not make a difference though.

good call. I did rotate all 4 calls completely through, and the gc doesn’t seem terribly different between them

@mflatt after adding (collect-garbage)
your version beat the tail-call-optimized one 3 times in a row with even less gc time which is amazing to me. Thanks for making continuations so fast :slightly_smiling_face:

I have a Racket package that uses a Rust component over FFI; I want to deploy pre-build binaries

Right now, it works by creating custom branches in my repo that I commit Window, macOS, and Linux binaries to

And there’s a complex automated script that builds a new package on push and then commits it to the appropriate branch

Is there a better way to do this?

If there were a way to make use of Github Actions artifacts, for example, that would be a lot cleaner

Maybe GitHub releases are helpful?

Unfortunately artifacts expire after a while

The menagerie of similar concepts doesn’t help here

With releases it’s unclear how to have a prerelease version

Unfortunately raco
doesn’t seem to have a concept of multiple versions? It’s not clear to me

And pre-release / release versions?

Good Morning. how are you?. I have a question, why does this code return this? #<piece>
This is the only thing that I have done (define-struct piece (space1 space2)) (define p1 (make-piece 0 0))
(define p2 (make-piece 0 1)) and when I call in the console, for example p1, it returns #<piece>

@dcmicoltacespedes If you have defined piece
as a struct your-self, then add `#:transparent).

(struct piece (space1 space2) #:transparent) (define p1 (make-piece 0 0))

btw is struct
the same as define-struct
?

Almost. The way structs are defined were tweaked at some point. define-struct
is the “old fashioned” way.

For simple struct definitions they are the same.

ok i guessed something like that. didn’t find much on define-struct so i just used struct. And thanks for your help @soegaard2 I ordered my print a few hours ago :slightly_smiling_face:

(regarding the guide)

struct is another way to define structures? or what is the modified form of define-struct?

I am looking for something like Treemaps from Gauche scheme, or any other ordered dictionary data structure. Can anybody point me in the right direction please?

@dcmicoltacespedes Yes struct
is the standard way of defining structs. (Maybe they used define-struct
in HtDP - I have forgotten). They are almost the same for standard structs.

@code Gauche’s treemaps look like mutable balanced binary trees, right? The closest thing that Racket ships with is data/splay-tree
, I think.

There are definitely some implementations of immutable balanced binary trees out there.

@code Hash table?

And I wouldn’t be surprised if there were some mutable ones.

I assumed he wanted an ordered map.

Yeah: here are some mutable red-black trees https://docs.racket-lang.org/data-red-black/index.html

Good point - the entries aren’t ordered by key in hash tables.

exactly, I need a key value store that preserves insertion order. So I can treat it as a sequence

Q about the package server: I rescanned my package egg-herbie
, and the package server now shows the correct checksum, but when I request that package (from GH actions) it still gets the old commit.

Oh, well insertion order isn’t what you normally get with these data structures.

You get key order.

But someone definitely put together a dict that preserves insertion order not too long ago. I’m sure I can find it in my email.

Er, this one gives you LIFO order: https://docs.racket-lang.org/ddict/index.html

But I guess you want FIFO?

Because I think that was the package I was thinking of.

Keep insertion order? Are you looking for a queue?

I’m sure the PFDS library has stacks queues and deques

My understanding is that @code is looking for a dictionary, where the iteration order is the insertion order.

Which is actually common in a lot of languages where dictionaries are used… uh, promiscuously.

alist
?

Alists are LIFO, too.



@samth That’s what I pointed to above, but it maintains LIFO order, not FIFO

I am looking for a datastructure where i can refer to elements both by index and by key (a string in my usecase)

something that R has where you can have named vectors

Like the sort of thing you’d use to implement an LRU cache, it sounds like.

Well, I guess you wouldn’t use an index there.

Is it cheating to keep a Vector of your keys? You’d have to write some wrappers/helpers to make it nice to work with.

I can probably implement this as a struct combining a vector and a hash that maps the key to the position in the vector. Just wanted to check if any such structure already exists

Can you remove elements by either key or index?

I think @jaz is right. splay trees must be it. https://docs.racket-lang.org/data/Splay_Trees.html?q=queue

Those are key-ordered, like most search trees.

Good point. If I want to remove by index I would also need to keep track of index->key mapping

I’m looking at some documentation on named vectors in R, but it’s not very comprehensive. Maybe I’m looking in the wrong place.

Eh, I found something more informative. It looks like you have a vector, and you’re allowed to assign names to the indices. It’s maybe more like tuples in a relational database.

But not all the indices need to be labeled.

(Well, ok, and in the database the names exist for the whole relation not just the individual tuple.)

you are right, documentation is hard to find even though it is a base function https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/names This says names is an attribute of a vector or list. I will look for some implementation details and see if I cam reproduce this on racket

looks like the implementation is some internal C code, incomprehensible to me

@roshansh has joined the channel

@akuzma has joined the channel

Is there a better way than parsing the exn-message
string to determine the given and expected number of arguments for an arity error. A general solution would be nice, but currently it’s for functions I’m defining, so an alternative is to accept any number of arguments and then check. But dealing with the list of arguments seems like it could introduce a noticeable slowdown for simple functions.

Well, if you also have the function, you can use procedure-arity
. But exn:fail:contract:arity
seems not to have the information, you need.

I wouldn’t have/know the function where the error is handled, although that too would be nice to have. Would placing continuation marks be a reasonable approach.

You can use case-lambda
with one case with the expected number of arguments and another that accepts any number. That should perform well (and inline well, etc.).
As you say, the exn for an arity error does not include the arity, currently, except sometimes in the message.

Oh, I was avoiding case-lambda
historically because of https://github.com/racket/racket/issues/3234 and was rewriting error messages for functions I wasn’t necessarily defining. But, unsurprisingly, timing it with a catch-all clause for incorrect arities has no noticeable overhead. It still seems like standard exceptions in racket could contain more information than just the message. Is there a reason they don’t?

Don’t know. It would be natural for the exception to hold that information.

At times, I’ve tried to add more information (at least to the message text) and it hasn’t be available on all compilation paths. For example, the expected number of arguments (i.e., the full arity) might be one of those things that isn’t always available right now. I think the number of actual arguments is available now, but I’m not sure about even that.

Since it’s a question of the information being available you can close the issues as far as I’m concerned, since the current effect is for functions I can redefine using case-lambda
s that “catch” the error, and probably prefer that to parsing structured text. The standard teaching languages rely on rewriting, but you’re probably familiar with that. They only procedure-rename
once (for something about signatures, which has a possibly unrelated todo comment) and a skim shows most of the case-lambda
s look internal except one jumped out and is now filed as an issue in racket/htdp.

I submitted a SO question: https://stackoverflow.com/questions/62225401/collect-values-in-an-internal-definition-context

nvm, it works now… deleting the question.

Instead, answer your own question

Ah, sorry

Will do it next time