
egads, someone doing metaprogramming nicer than racket! https://docs.rs/structopt-derive/0.1.5/structopt_derive/

is that nicer ?

@apg the syntax is pretty ugly, but it’s getting a lot more than what we do for cmd line options

in particular, auto-parsing from the struct definition

just requires rolling up the sleeves and doing the work though. :slightly_smiling_face:

I’ve wanted that for a while, fwiw. Haskell has optparse-generic, which does a similar thing.

But this is all way nicer with ~~typeclasses~~ because you can use the type information to know how to parse each field. :)

(And Rust has traits, which I imagine can do the same thing here.)

yeah

plus annotations on struct fields

annotations on struct fields would be great

@lexi.lambda oh I’ve been meaning to ask you: what approaches to hackett’s type-value namespaces didn’t work?

@notjack I tried a few slightly different things before I got something work, but most of the dramatically different things that wouldn’t have worked I dismissed without trying

I think the most significant difference between my first attempt and the current implementation is that I originally tried having different type/value scopes per module instantiation, but that ended up being needlessly complicated.

the only remotely plausible alternative approach I thought about was to use phases instead of scopes, but that didn’t really hold up to scrutiny.

I’m wondering if using the same approach within a module but doing one of the following instead of name mangling might work:
- Providing from one of either a
value-namespace
or atype-namespace
submodule, with hackett’srequire
looking for those submodules and adding type/value scopes to imports based on which submodule they came from (maybe the parent providing module should provide the scope introducer functions it used as well? not sure) - Providing syntax bound to a struct containing a field for a value identifier and a field for a type identifier, each having their type/value scope already added, with hackett’s
require
recognizing these bindings and unpacking them.
But I don’t know how much work either of those would take to make them cooperate with scribble.

The problem with both of those approaches is that it makes it very difficult to make them transparently work with require
and provide
.

Specifically, you want to be able to do things like (require (rename-in [Tuple tuple]))
and have it only rename the value-level Tuple
.

that’s already rather painful no? You have to rename-in the #%hackett-type:id
form

So packing things together doesn’t really work. And you can’t easily lift the appropriate values into submodules when to do provide
.

It might work if you did the packing with an entirely custom provide
form?

what other kinds of requires get painful besides rename-in
?

The trouble is that require
can only be customized so much… you can’t make a require
introduce a new syntax binding.

oh dang you can’t?

No, provide transformers can lift, but they can’t expand to a definition.

hm wait

I think I tried hacking something with syntax-local-lift-module
, but IIRC the lifted module isn’t available when the require
is expanded, so you can’t require
it in the expansion.

confused about which of these is possible:
- provide transformer introduces new normal binding and exports it
- provide transformer introduces new syntax binding and exports it
- require transformer binds and declares import of new normal binding
- require transformer binds and declares import of new syntax binding
and which lift
functions are used for this? just syntax-local-lift-*
stuff or things that are specific to require/provide?

Yeah, it’s syntax-local-lift-*
. And note that provide pre-transformers can lift, but provide transformers can’t… and only provide transformers have access to the set of bindings imported/exported when doing something like (provide (all-from-out foo/bar/baz))
.

also: do these require/provide limitations have good reasons for existing, or could some patches to the require/provide system implement them without much issue?

I looked at the source code for Racket’s require
and provide
, and I examined #%require
and #%provide
a little.

Here’s what I learned: require transformers and provide pre-transformers are implemented in Racket. Provide transformers are implemented in C.

I think provide transformers are pretty restricted because they have access to the bindings exported by all-from-out
and things like that, but in order to know that, the module needs to know which bindings are shadowed by the module body. So provide transformers are essentially the very last step of macro transformation in a module’s expansion.

This is a bit tricky, since it means provide transformers can’t do any lifting, but it means provide pre-transformers can’t know the precise set of bindings being exported.

Require transformers can do pretty much anything by comparison, but “anything” is restricted by the fact that it can only expand to #%require
clauses and lift things. That restriction could probably be lifted, providing some API to make a require transformer expand to a fresh definition? But you’d have to be careful, since an imported definition could be hidden with only-in
or something similar.

commuting; will read in more detail later. Off the cuff thought: wondering if the racket implementation of the macro system will make changes here possible / easier

The provide
restrictions are semi-fundamental AFAICT, and require
transformers are already implemented entirely in Racket, so my gut says “no”, but it’s possible I am being insufficiently creative.

I would be curious one day to see an indentation-based Lisp

A Lisp with minimal parens!

I notice that Lisp users kind of already have an indentation-based organization


It looks like that was a scheme proposal


where have I seen infix curly brace notation :thinking_face:

Hmm most results look more readable in srfi 110

Some are mixed results

My biggest issue is when switching back to a lisp after writing in languages with more typical syntax

Like earlier today, when I mixed up (<= 1)
and (lambda [x] (<= x 1))
, because Hackett’s partial applications look like Haskell’s operator sections