I’m pretty sure that C is, to some extent, usually a wrapper over Fortran too :smile: (since most BLAS/LAPACK implementations are still done in Fortran, and I’m moderately certain Numpy uses BLAS under-the-hood)
I was wondering whether if
and friends only consider #f
as false or if there may be other falsey objects?
Only #f
and #false
are false values. This is one of the cleanest things I love about Racket. It makes reasoning easy. (I think I saw some discussion about increasing the set of falsy values, IMO that would be a big mistake)
In particular, 0
, #<void>
(or (void)
), '()
are not false values
Thanks!
#f
and #false
do not refer to the same thing?
They do
Cue my olden-days story about the GAP programming language where a boolean can be true, false, or fail
(or the even worse story of the value SuPeRfail
)
Open the View
menu and choose Show Log
.
The edit control lets you enter a syntax similar to the command line, for what levels of which topics you want to see.
Oh weird, Slack refreshed very slowly for me. I just replied to them above thinking it was the last message here.
I mean, punning nil
a.k.a. '()
to mean “false” is bad. But punning false
(#f
) to mean “no value” also isn’t wonderful, compared to an option type like “Maybe”, I think? So it seems like they had a good intuition. But I know nothing about GAP and I fully accept your claim that the implementation was horrible. :slightly_smiling_face: (The idea that SuPeRfail
means something like “no really! I mean it!! there’s no value!” seems… interesting.)
well superfail was the outcome of a not thought through pattern: you pass a function and parameters to a function, and then want to either return the value the function returned or the fact that the execution of the function failed.
Apart from the quality of the implementation, the name itself seems a terrible choice
“If the stack overflows, let’s call this Megafail!”
what happens if the function you passed into your function returns superfail itself tho
There are quite a few BLAS/LAPACK implementations. So many it can be confusing.
The original in Fortran (which can be compiled, so it can be called from C). A version that stems from running a C->Fortran translator in the original implementation.
And a lot of reimplementations. One is made by Intel. Some suggest that implementation runs slowly on AMD-processors!
@markus.pfeiffer GAP? The one used make group calculations?
@markus.pfeiffer That one is easy, it’s a supersuperfail of course
> The registration will open around the end of November. FYI
Thanks so much!
@soegaard2 yep
An interesting macrology question based on toying with Beautiful Racket (not my question): Why does this code: (define-macro-cases bf-op
[(bf-op ">") #'(set! ptr (add1 ptr))]
[(bf-op "<") #'(set! ptr (sub1 ptr))]
[(bf-op "+") #'(set-current-byte! (add1 (current-byte)))]
[(bf-op "-") #'(set-current-byte! (sub1 (current-byte)))]
[(bf-op ".") #'(write-byte (current-byte))]
[(bf-op ",") #'(set-current-byte! (read-byte))])
(provide bf-op)
(define arr (make-vector 30000 0))
(define ptr 0)
(define (current-byte) (vector-ref arr ptr))
(define (set-current-byte! val) (vector-set! arr ptr val))
…yield this error: expander.rkt:21:23: set!: cannot mutate module-required identifier
at: ptr
in: (set! ptr (add1 ptr))
location...:
expander.rkt:21:23
(line 21 in the error is line 2 above) …but this code: (define-macro-cases bf-op
[(bf-op ">") #'(update-pointer add1)]
[(bf-op "<") #'(update-pointer sub1)]
[(bf-op "+") #'(set-current-byte! (add1 (current-byte)))]
[(bf-op "-") #'(set-current-byte! (sub1 (current-byte)))]
[(bf-op ".") #'(write-byte (current-byte))]
[(bf-op ",") #'(set-current-byte! (read-byte))])
(provide bf-op)
(define arr (make-vector 30000 0))
(define ptr 0)
(define (current-byte) (vector-ref arr ptr))
(define (set-current-byte! val) (vector-set! arr ptr val))
(define (update-pointer f) (set! ptr (f ptr)))
(i.e. with the set!
call pulled out to a helper function) …work fine? Does define-macro-cases
not allow you to have a set!
call in the top-level expansion yet allow it one level indirected?
This isn’t a macro-related restriction — all set!
of a variable must be in the module that it’s defined in, and macros don’t let you circumvent that.
Well, the level of indirection vs. expansion does sort of confuse the issue, esp. to a beginner. My comment was something like > I can’t quite trace it all the way through, but I think the issue is that the version that expands without set!
directly is acceptable because of hygiene (the set!
call still lives in the module as the value). But in the other version, the set!
shows up in a module while ptr
is still (syntactically, because hygiene) a reference to a value from a different module? Is that even close to right?
The error message doesn’t really help here, since it’s not obvious how ptr
is module-required (esp. to a beginner).
no, there’s no relation to hygiene
but the broader point is right — when you expand the macro-version, the set! goes in the other file
and that’s not allowed
If I understand correctly (not my question either, a user in our local slack), they aren’t explicitly requiring the module that has the identifier being complained about. Is there something about the macro expansion that implicitly requires the module, and thus, produces the error about a “module-required identifier” ?
^that’s where I drug hygiene in: the identifier isn’t even exported, so I assumed the ability to reference it in the expanded module had something to do with hygiene
(I’m assuming it isn’t provided, anyway)
I asked for more info in our other slack :)
saw that, my follow-up clarified my assumption there
well, whether that has to do with hygiene sort of depends on what you mean by hygiene, but the check doesn’t have anything to do with whether something is required or not
The error message is: “expander.rkt:21:23: set!: cannot mutate module-required identifier” which does seem to indicate require
is relevant.
I understand that that’s the error message but it doesn’t have anything to do with require
I guess I don’t understand what a “module-required” identifier is.
I think that error message means “identifier from another module” but it is not a good error message
Ah. Yes, I like your error message better :)
For any json
users, is there any reason why a hash
with string?
keys should not be a jsexpr?
? In other words, unless I’m missing something, it seems both lines below should return #t
: (require json)
(jsexpr? (hash "foo" "bar")) ; => #f
(jsexpr? (hash 'foo "bar")) ; => #t
In the context of a web app, field names will typically be identified with strings, so having to convert between symbols and strings seems like an unnecessary hassle.
The prescriptivist reason is that that’s how the module defines the data type
Strings are mutable so it’s best to avoid using them as keys. Also hasheq is more efficient than hash
I’m not sure how that applies here. I’m not asking whether or not one should use strings as keys in a hash. Assuming you do have a hash with string keys, why can’t you use it in jsexpr->string
?
Or, in other words, what disadvantage is there to allowing that to happen?
I’m pretty sure jsexpr->string
is going to call symbol->string
when producing the output.
Those are the reasons that the data type is restricted to symbols. The jsexpr->string
could certainly be more broad, but it isn’t.
(I’m not responsible for the package, I just use it)
The “keys must be symbols” constraint is helpful (I think) for functions like read-json
that produce something you need to process, and jsexpr?
is the (stricter) contract there. Given that, it makes sense for something like jsexpr->string
to take, you know, a jsexpr?
. :slightly_smiling_face:
I think maybe you (or even the jsexpr package) could define a wrapper function that takes a hash-table with string?
keys, converts them, and calls jsexpr->string
. It can have a looser contract.
Maybe someone even wants the keys to be any/c
, and does ~a
and string->symbol
on them to make symbol keys.
So I think the question of how “loose” to go the other way, maybe is fine to leave up to each user of the package?
At least that’s how I’d defend it if I were paid to. :slightly_smiling_face:
The PR authors no longer use Racket though. So unless someone wants to take it over, it probably won’t get merged
Reading JSON is an entirely different thing. I still see zero reasons to force a user of json
to convert a key from a string to a symbol, just to have jsexpr->string
convert the symbol back to a string.
I’m not saying there are no reasons, just none articulated yet.
One argument against allowing string keys is to avoid having to consider how things like (jsexpr->string (hash 'a 1 "a" 2 (string #\a) 3))
should behave.
Wouldn’t that simply result in the following JSON string? { "a" : 1, "a" : 2, "a" : 3 }
IMO, that would be bad.
Yeah, I typed in haste. I assume you’re implying the json
module has some validation along these lines.
According to my Chrome javascript console, attempting to create the object { "a" : 1, "a" : 2 }
results in { "a" : 2 }
So your example would end up as { "a" : 3 }
My point is that with symbol keys, you don’t even have to do validation. (Really, jsexpr should be restricted to interned symbols, and I’m not sure that is enforced.)
That’s a property of JS syntax, not of the JSON printer, though
What you wrote is the equivalent of #hash((a . 1) (a . 1))
(jsexpr? (hash 'foo "bar" 'foo "foo"))
=> #t
that only has one entry, though
The hash @ryanc mentioned has 3 entries
JavaScript evaluates left to right, so I still think the result would be { "a" : 3 }
no, that’s not relevant
Except Racket probably doesn’t preserve order here … :(
{"a":3, "a":2}
is not valid JSON
Ok, thanks @ryanc - I accept your disadvantage :)
Rails has something like HashWithIndifferentAccess which is kind of horrible.
IIUC, it is valid, but the JSON spec just shrugs at the question of what duplicate keys should mean.
I suppose I could change: (define (form-values req)
(for/hash ([ b (in-list (request-bindings/raw req)) ])
(cond [ (binding:form? b) (values
(bytes->string/utf-8 (binding-id b) #\space)
(bytes->string/utf-8 (binding:form-value b) #\space)) ]
[ (binding:file? b) (values
(bytes->string/utf-8 (binding-id b) #\space)
(binding:file-content b)) ])))
to use symbols, but I’ll need to ponder that for a while. The keys are coming in as strings (essentially) from HTTP, and strings seem to be a reasonable choice for the keys in this case. The pathological case above seems a bit contrived.
@popa.bogdanp do you convert form values to a hash with symbol keys?
Following
My current project is new, and not huge yet, so I just changed the above code to: (define (form-values req)
(for/hash ([ b (in-list (request-bindings/raw req)) ])
(cond [ (binding:form? b) (values
(string->symbol (bytes->string/utf-8 (binding-id b) #\space))
(bytes->string/utf-8 (binding:form-value b) #\space)) ]
[ (binding:file? b) (values
(string->symbol (bytes->string/utf-8 (binding-id b) #\space))
(binding:file-content b)) ])))
and fixed-up the rest of the code to match, and so far, so good :) I think I’ll stick with symbol keys for now.
Using symbols everywhere avoids the madness of Rails’ HashWithIndifferentAccess
That looks good to me. In fact ISTR writing a little bytes->symbol
function composing those two and using it in situations just like this.
Creating color maps isn’t trivial. I recommend not using the rainbow color map. :slightly_smiling_face:
Here are a few links that I find interesting: https://www.kennethmoreland.com/color-advice/BadColorMaps.pdf https://www.kennethmoreland.com/color-advice/ https://www.kennethmoreland.com/color-maps/
where does that message come from? I’d like to change it
This is so much better now :) I’m glad the group talked me down from heading down the “using both symbols and strings with hashes” road :) Nothing to remember now - it’s always a symbol.
The color maps defined in the colormaps package are not mine, but sourced from different places. The rainbow one comes from here: https://personal.sron.nl/~pault/, I will have a read of the website you linked to, and see if I can extend the package with additional color maps.
I’ve done this with a “server” that I start via system*
or similar and just talk to over standard IO in JSON or something, without any HTTP or whatever.