@eriksilkensen has joined the channel
@dnaeon has joined the channel
What’s the meaning of the error I’m getting? For this code: #lang typed/racket/base
(require typed/racket/class)
(define-type Foo<%> (All (A) (Class (field [bar A]))))
(define-type Foo (All (A) (Instance (Foo<%> A))))
(define (baz [f : (All (A) (Foo A))])
(get-field bar f))
I get Type Checker: type mismatch;
expected an object value for get-field
given: Foo in: (get-field bar f)
My understanding is that since type Foo
stands for an Instance
of some class, get-field should be fine with it, no?
@abbyrjones72 While SICP is an important and influential book, there are ways in which it is more difficult than it needs to be. Racket’s roots include, in part, the goal to improve on it. You might be interested in the paper “The Structure and Interpretation of the Computer Science Curriculum”, by Felleisen et al., which goes into more detail. https://www2.ccs.neu.edu/racket/pubs/jfp2004-fffk.pdf
@plragde thank you for this. :slightly_smiling_face:
How to Design Programs is another free book, and is written by some of the people behind Racket
Inertia is my friend here. I start my new job on Monday so I will have less time to write code, but I will have a few hours before sleep to do some reading.
Yeah, reading this paper it’s clear that the SICP is great, but what I’m doing is the equivalent of studying C to become better at C++. Two different things. I’ll switch to HTDP/2e this weekend to give that a look.
I think HtDP will give the general concepts and ergonomics for Racket, though. The methodology is what’s important. The particulars (knowing which for
variant to use) aren’t quite as important. I think C/C++ isn’t quite the right comparison, since really HtDP is a subset of Racket that you could use thoughtfully very productively, while if you wrote K&R-style C in C++ it would be a terrible idea :stuck_out_tongue:
That being said, I can empathize with the feeling that Racket is just a really big language that seemingly goes on forever, and it feels uneasy to use a subset that isn’t the “whole thing.” I felt that way when learning Racket from Scheme.
The part of Racket that’s hard to learn as a beginner is the extensible features of the language, treating the language as a compiler and language building framework, rather than a static thing (the way we’re used to learning languages) .
@samth you mentioned that with-syntax
was just a macro on top of syntax-case
, which makes sense after reading more about syntax case and syntax
. Any pointers on places—short of the actual Racket source—that would help build more fine-grained intuition about the macro system in this way? I presume I just need to dig through some papers on it.
the documentation has some good bits of insight scattered throughout.
I suspect I won’t really get this until I write a hygienic macro expander myself..
For me, understanding how to pass values between macros using define-syntax
and syntax-local-value
made a lot of other stuff click into place
ok, that’s good advice
How did you learn how to do that, just play around with a bunch of examples?
I haven’t seen syntax-local-value
, is that something that messes with the scope sets on syntax objects?
okay, I see what’s going on here. I also feel like I’d get what’s going on if I could see how it all expands down to fully-expanded racket. Looks like all of this ends up expanding down to define-syntaxes
and such.
Playing with examples, as well as learning that it’s used to implement these things:
- match expanders
- struct transformers (the static info about a struct)
- syntax-parse pattern expanders (and probably syntax classes)
Basically, whenever you need a way to pass around data at compile time between macros, syntax-local-value
should be involved somewhere
that makes sense
The best tutorial for syntax-local-value
is https://www.cs.utah.edu/plt/publications/jfp12-draft-fcdf.pdf, section 2.1, IMO
Also there’s a really really good chapter somewhere in the racket guide about how modules, phases, and define-syntax
interact
great, this is really helpful.
Oh! One more thing that really helped me: the macros as sets of scopes paper and model. Specifically, it helped me a lot to think of identifiers as just strings plus sets of scopes. All of the information for keeping two identifiers with the same name distinct is encoded only in scopes. You don’t actually need gensym
at all, and if you find yourself using it in a macro what you probably want to do instead is to create a new scope. You can make your own scopes using make-syntax-introducer
, which is named that because the API existed before the set-of-scopes model. A more modern API would probably be something like make-scope
combined with identifier-add-scope
.
Yeah, I watched a video by Matt Flatt a few times about this
Yup that one!
watched this 3–4 times and then read examples..
the scope sets idea is great, but I don’t have a clear idea about how scope sets relate back to what will get expanded using which set of bindings, etc..
yeah I think it’s hard to connect the scope set ideas to the current racket syntax APIs
The APIs would probably look a lot different if they were developed after scope sets were figured out
yeah, this is one challenge I have. There are a few different layers here that all interact in fairly subtle ways
It’s not just you. There’s a lot of things that could be done to make the macro system more accessible.
Yes, this “macros that work together” paper is pretty good
It’s much more uniform in its economy of using the macro API.
I also get confused here because papers often use the term “compile-time”, but I realize this is just an approximation of what really happens: racket has multiple phases that expand various things, and so reconciling that high-level notion with the actual implementation is sometimes a bit tricky.
@krismicinski I find your comment a bit confusing, because there are a few different things in play here (1) the basics of Dybvig-style procedural macros, using define-syntax
, syntax-case
and syntax
(2) Racket’s extensions to those (3) how hygiene works at a non-slogan level (4) the pragmatics of sophisticated metaprogramming in Racket
your confusion about with-syntax
and syntax-case
seems to be mostly in (1) but you’ve gotten answers mostly about the others
I would recommend Dybvig’s “writing hygenic macros in Scheme with syntax-case” as a great macro-writing tutorial
perhaps especially because it doesn’t treat any of the other more complex topics
Has anyone else ever wanted an alternative to make-struct-type
that uses keyword arguments?
@samth yes, thanks for the pointers. I read through this over the past few hours and it has been a great reference. My apologies, I’ve never properly “learned” macro-based programming, only superficially hacked around it..
I’ll think over this for a few days and work through the examples and see if I have more questions after that..!