@sydney.lambda Nice idea. If you are interested in an example of how to implement basic types, you can look at types.rkt
and compiler.rkt
from MiniPascal. The compiler is on purpose simple and has a lot of comments.
@synth has joined the channel
@samdphillips Thanks, the 2nd edition is the one I own so that’s good to know. The later editions seems to be a bit meatier in those sections, but there’s plenty for me to be getting on with in the 2nd edition for sure. I think what I was considering last night could be considered an interpreter that computes types: having a tenv argument that gets passed along which records the type of each bound name; “apply” would then compare the types of the evaluated arguments with the types of the expected/declared arguments, and the type of the evaluated function with the expected/declared return type. @soegaard2 Seems to be just what I was looking for, thank you :slightly_smiling_face: I’ll be having a good read tonight to see how much I can grok.
@sydney.lambda Don’t hesitate to ask if something looks odd.
@soegaard2 Thanks :slightly_smiling_face:
@soegaard2 apologies in advance for my lack of syntax-parse knowledge. In this piece of code: (define (compile-simple-type stx)
; simple-type : type-identifier \| index-range
(syntax-parse stx
[(_ (~and sub ((~datum type-identifier) . _)))
(compile-type-identifier #'sub)]
could you give a layman’s explanation of what’s happening here? I’m struggling to imagine what an actual “concrete” piece of syntax that would be matched by this case would look like.
sub
is being bound to something in the event that the piece of syntax encountered is a type-identifier? Then it gets compiled.
A concrete piece of syntax that might match would be (compile-simple-type (type-identifier 42))
, and sub
would be bound to (type-identifier 42)
.
ah, so ~datum is just literally “type-identifier” or whatever text comes after ~datum. Thank you, I thought it was ensuring something was a type-identifier, or something like that.
Yes, (~datum x)
matches x
as a literal datum, in the same way as if x
was provided to #:datum-literals
.
Thanks :slightly_smiling_face:
Just out of curiosity (this is all very new to me) if you used: #:datum-literals type-identifier
, would it end up being: [(_ (~and sub (type-identifier . _)))
...
instead?
Yes, that’s right (though it would technically be #:datum-literals [type-identifier]
).
I see, thank you very much.
If I have a list of keys like so: '(x y z)
and a list of values like so: '(1 2 3)
what’s the best way to create a hash table out of them that maps x to 1, y to 2, z to 3 and so on?
I’m currently using: (let iter ([vars vars] [vals vals] [env env])
(if (null? vars)
env
(iter (cdr vars) (cdr vals) (hash-set env (car vars) (car vals)))))
but I figure I’m missing one in the stdlib.
(make-hash (map cons ks vs))
or (for/hash ([k (in-list ks)] [v (in-list vs)]) (values k v))
IIRC the first is actually faster in microbenchmarks, anyway (though I suppose it might allocate more), so you probably might as well use the shorter version
Thank you :slightly_smiling_face:
I’d then have to combine it with the already-existing hash, right?
hash-union seems to work okay. edit: sorry, I didn’t even mention I wanted to add the new bindings to a preexisting hash.
yeah, hash-union would be the easiest (and probably best) way
something like this would work as well (for/fold ([h old-hash]) ([k k*] [v v*]) (hash-set h k v))
(hastily typed)
yeah, that would do it directly. it may or may not be more efficient, for some notion of efficient.
yes, that’s much better than the named let; I need use for/fold more.
Thank you both :slightly_smiling_face:
for/hash
is just that for/fold
with an empty initial hash