
yeah

Yep I see :thinking_face: I tend to feel like imperativity isn’t too bad, as long as it’s controlled and encapsulated within functional interfaces. I like Rust a lot for that reason.

Also I find some stuff easier to express imperatively, but that’s probably because it’s all I’ve done for my first ten years of programming? :sweat_smile:

Yes, functional APIs is usually the style I (try to) use. :slightly_smiling_face:

> Also I find some stuff easier to express imperatively, but that’s probably because it’s all I’ve done for my first ten years of programming?
Yes, that’s most likely the reason. :wink: It also took me a while to get used to FP style.

Yeah that seems to be the usual experience :D

Regarding the typical recursive factorial
example, I went from “Who would actually do this?” to “Ok, you could do that.” to “Why not?” :smile:

Yeah I remember learning the basics of functional programming at university, like, five years ago, and thinking it was bonkers and uselessly complicated :sweat_smile:

But yes, I’m also much more fluent in imperative programming, but I enjoy the “flow” of FP. And of s-expressions.

I really didn’t think I’d ever enjoy writing with sexps. When I started learning Racket, I thought I’d just have to live with it. But then surprisingly quickly I came to understand and like it

I think if we add this to the standard library, it should have an #:ordered?
keyword argument that defaults to true that indicates whether the cartesian product should be iterated in the standard order

I didn’t know there was a “standard” order, but rather a “typical” order.
#:ordered?
would be somewhat confusing because the second version orders the yielded items, too, just in a different order.

In the context of iterating over multi-dimensional arrays, I saw the term “faster changing index” (or similar), but I guess we should try to find better terminology. :slightly_smiling_face:

FWIW, a few days ago I came across a Python program where I specifically needed the order from @sorawee’s second implementation. But I found you can convert from cartesian-product
by reversing the input sequences and the yielded/returned items.

But of course the reversing, which I did with (map reverse cartesian-product-result)
in my Racket experiments, rebuilds the whole outer list, which costs time and memory.

I would guess that most people would assume the order of a cartesian product is the same order that the equivalent nested for
loops would iterate in

@notjack Yes, most likely. If we have a “default order”, it should be this one from cartesian-product
.

but that’s an inefficient order to iterate in if the input sequences are very large (or infinite)

for instance, I think (in-cartesian-product (in-naturals) (in-naturals))
is a totally reasonable use case

If this is nested, it would stick to 0 for one index though?

If you want something like (in-cartesian-product (in-naturals) (in-naturals))
to work, I suggest the bijective enumeration

yes, which would be bad - I can’t imagine a user who’s providing infinite sequences as input would not want to also specify that they don’t care what order the products are iterated in

I think ordered by default and bijective if the client specifies unordered would be reasonable

I’m biased though - I recently hit this same issue while designing the transposing
transducer in rebellion, and I went with that approach: https://docs.racket-lang.org/rebellion/Transducers.html#%28def._%28%28lib._rebellion%2Fstreaming%2Ftransducer..rkt%29._transposing%29%29

(require data/enumerate/lib)
(define my-enum/e (cons/e natural/e natural/e))
(for/list ([x (in-enum my-enum/e)] [i 100])
x)

nice :p

at least we have somewhere to copy the algorithm from

Nice. Very nice. :slightly_smiling_face:


There are two possible ordering for cons/e

oh wow it even does the ordering thing

Yeah, otherwise it wouldn’t be bijective :slightly_smiling_face:

I mean the keyword argument to control ordering part :p

Ah, right

> (enum->list (cons/e natural/e natural/e #:ordering 'square) 10)
'((0 . 0) (0 . 1) (1 . 0) (1 . 1) (0 . 2) (1 . 2) (2 . 0) (2 . 1) (2 . 2) (0 . 3))

> If ordering is ’square, it uses a generalized form of Szudzik’s “elegant” ordering and if ordering is ’diagonal, it uses a generalized form of Cantor’s mapping from pairs of naturals to naturals.


hmm

which of those is…. good?

what on earth is “Szudzik’s elegant ordering”


huh

neat, and I think that should actually be the only option for unordered in-cartesian-product
because it won’t look at the n+1th element of any input sequence before exhausting all possible combinations that can be constructed by looking up to the nth element of every input sequence

so it maximizes laziness

I don’t know how to use the bijective enumeration with sequences though

Like, we can convert a bijective enumeration to a sequence

But I don’t think the opposite can be done?

There’re special cases like natural/e
, but not any sequence in general

yeah I think you’d have to rip out the algorithm and reimplement it in terms of plain sequences that are iteratively evaluated



@samdphillips Hi. Following your lead, the sketching now builds and deploys its docs directly. The trickiest part (after seeing how you used James Ives github-deploy-action) was to get the path right. It helped, when I inserted an ls -r *
to see what was going on…

Just to tie up this loose end. While I’m still not sure why the contract error message is missing one of the arguments on my production system running Racket 7.3 BC, I was able to recreate the scenario on my dev machine running Racket v8.1.0.6 [cs], and the contract error message is correct. It appears to be a bug in 7.3 exhibited by my particular scenario, but since it seems fixed (if it was a bug) in my current version of Racket, I’m not going to dig any further.

So I’m trying to narrow down unexpected behaviour with dynamic-rerequire
(it won’t reload a file if the source file itself hasn’t changed, but a dependency has)
I’ve fixed this when loading from source (by having it reload if the timestamp is newer, OR if a dependency was reloaded), but the fix doesn’t work if they’re being loaded from .zo files (built using raco make --disable-constant
)
What I’ve discovered is that if you have a directory called “private” that contains “a.rkt” and “b.rkt”, and a
requires b
then module-compiled-imports
gives a list that contains #<module-path-index:"b.rkt" + a[4893]>
So far so good. But when check-latest
is descending through the dependencies, this module-path-index doesn’t seem to behave correctly.
If I use module-path-index-resolve
on that module-path-index?
then the behaviour depends on how those files were loaded. If they were loaded from source, then I get a path to the “b.rkt” file I expect, "./private/b.rkt", and if this file gets reloaded then with my patch, “a.rkt” also gets reloaded.
If they were loaded from a .zo file, then instead I get an path that tries to point to “b.rkt” in the current directory e.g. "./b.rkt" (which isn’t where it is located). Since that file isn’t in the cache, the loop does not descend into that dependency (meaning b.rkt will not be reloaded).

I’m not sure what’s happening, but when a “.zo” file is loaded, the resolved module path and/or current load-relative directory should be set to the “.rkt” file name, as opposed to the “.zo” name, while loading the code. But assuming that you haven’t changed the way rerequire-load/use-compiled
uses get-module-code
, that should be done right already.

.. or maybe it isn’t done right already, and that’s where the problem is

I didn’t touch rerequire-load/use-compiled
only the loop inside check-latest

On reflection, I guess get-module-code
doesn’t tie the loaded code to the file that it was loaded from. So, probably those module path indices from module-compiled-imports
need to be rebuilt on a module path index in place of the “self” one that has the “.rkt” file’s path.

Otherwise, module-path-index-resolve
will use the current [load-relative] directory.

Another approach to repairing the current code may be to use resolve-module-path-index
function, which lets you provide the “self” path as the second argument.

Alright, I think I had something working along those lines but wasn’t sure if this was due to something deeper that should be fixed

For lists there is map
and for-each
. For vectors there is vector-map
(and vector-map!
). Is there a reason there is no for-each
equivalent for vectors? I’m operating on a list which has tens of thousands (or more) items, and I take slices of them, so I turned the list into a vector.

I think the reason is that vector-for-each wasn’t in R5RS - and nobody thought of adding it to Racket. It’s in srfi/43 though.

thx

obviously there’s also just for
:wink:

Stickers are coming! Join the fun making Syntax Parse Macros & get your contributions in! https://github.com/syntax-objects/Summer2021/blob/master/ANNOUNCEMENT.md\|https://github.com/syntax-objects/Summer2021/blob/master/ANNOUNCEMENT.md

@gknauth there’s sequence-for-each

Is there a way (in _un_typed Racket) to check if two values have the same type? Hypothetical example: (define my-list '(1 2 3))
(define my-vector #(1 2 3))
(same-type? my-list my-vector) ; #f
(define my-list2 '(1 2 3 4))
(same-type? my-list my-list2) ; #t

No. But I think, you could get close with (equal? (description value1) (description value2))
.

It depends on what you mean by type…
For example, do a list of integers and a list of booleans have the same type? In one sense, yes, they are both lists. In another sense, no.

Good point. For the application I have in mind it would be better if the predicate only checked the “outer” type.

Just to add to the above… what about int vs. float and fixnum vs. bignum?

are ratio and float the same?


yes

@massung They would be different types for me. But now after thinking a bit more about it, I might get by without the type equality check after all. :smile:

and also in this case should '(5)
and (cons #f #f)
be the same? they are both cons cells

But as the others point out - you may need to roll your own, if your interpretation of “type” is different.

That’s interesting. In one sense they’re the same type (cons cells), but in another sense different types (not both are lists). But that’s actually similar to @massung’s point in that, for example, all four types are numbers.
So yes, I’ll make do without the “type equality” check. :slightly_smiling_face:

As a poor-man’s check, you could probably do something like (untested): (define type-predicates '(number? null? boolean? cons? hash?))
(define (type=? x y)
(findf (lambda (pred) (and (pred x) (pred y))) type-predicates))