Re: [racket-users] Generate function defintions at compile time
> On Aug 28, 2017, at 4:24 AM, Konrad Hinsenwrote: > > I found the implementation of the Video language on pkg.racket-lang.org, but > neither Typed Video nor Docu Video seem to be there. Are they available > elsewhere? I am particularly interested in Docu Video because I wonder if it > can be implemented as a composition of "Video" and "Scribble" or if it needs > to be defined from scratch, re-using only the implementation modules of > "Video" and "Scribble". Video Lang is Leif Andersen’s [CCed] project. I think ‘lang.video’ will become the actual site for the language, and you may want to watch it there. He has created updates, and I am sure the documentation language will make it to the repo/web site. Stephen created Typed Video as a demonstration project and as a teaser for the ICFP academic community (who is obsessed with types). None us actually thinks that a scripting language needs this kind of fancy type system. If you are interested in taking over, I am sure Stephen can sketch out what it takes to stay uptodate with Leif’s progress. — Matthias p.s. Do check out the CACM paper, which is a high-level, non-academic sketch of the same idea, appealing to Video Lang along the way. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
Matthias, If you would like to see a concrete example, fully worked out, see the ICFP paper on constructing a domain-specific language for scripting the production of videos (say RacketCon presentations): https://www2.ccs.neu.edu/racket/pubs/#icfp17-dnff At the surface, this could be done as a piece of two modules: the surface language (boring) and the run-time library that connects to existing NLVE systems. But as it turns out, if you truly take the slogan seriously, you can easily see how we build this application as a composition of EIGHT (8) DSLs, three used at the surface (Video, Typed Video, and Docu Video) and five below, inside the application. This is really a nice illustration of "The Racket Way". Please consider pointing to this on the Racket Web site. Or, better yet, put a less academic writeup on this example to the Web site. I found the implementation of the Video language on pkg.racket-lang.org, but neither Typed Video nor Docu Video seem to be there. Are they available elsewhere? I am particularly interested in Docu Video because I wonder if it can be implemented as a composition of "Video" and "Scribble" or if it needs to be defined from scratch, re-using only the implementation modules of "Video" and "Scribble". Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
> On Aug 24, 2017, at 9:38 PM, Alex Harsanyiwrote: > > Its all just objects, functions and function applications supported by some > library code. I could write a "#lang workout" with some macros to hide the > actual mechanism to make it look more "magic", but I don't see a value in > doing that. Then don’t and live happily with functions and objects ever after. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
On Thursday, August 24, 2017 at 9:42:51 PM UTC+8, Matthias Felleisen wrote: > > Yes, Racket is a good language. But let me point you to the blog of a > reflective developer, and I consider reflective developers the best of their > kind: > > > https://medium.com/@daveford/80-of-my-coding-is-doing-this-or-why-templates-are-dead-b640fc149e22 None of the work that I do could be described, as the blog author puts it, "writing code in one language (say Java or JavaScript) whose sole purpose is to generate a different language (say HTML)". This might affect my view of the world... Sill, if I understand the article correctly, the author suggests that people should use DLS's *not* that they should write their own. I was trying to make the argument that people starting using Racket should not be encouraged to solve simple problems by writing their own DSL, so I'm not sure the blog post disagrees with this. For the record, I also agree that DLS's, as written by experienced people, are valuable and should be used by everyone. > If you would like to see a concrete example, fully worked out, see the ICFP > paper on constructing a domain-specific language for scripting the production > of videos (say RacketCon presentations): > > https://www2.ccs.neu.edu/racket/pubs/#icfp17-dnff > I admit that I only skimmed the article, it is after all 27 pages long :-), however this video DSL is written by experts, not by people who started using Racket last week. Looking at the code example in the paper, it seems to me that the definition of a DSL is a bit different than mine. In particular, it is not clear to me when a collection of library functions becomes a DSL. For example, I have some Racket code that allows me to generate FIT workout files for Garmin devices (these are binary files that encode information about a structured running or cycling workout). With the library, I can create workouts like this: (require "al-workouts.rkt") (define (hr/warmup) (hr/bpm 60 163)) ; Z1 + Z2 (define (pace/hard) (speed (pace 4 29) (pace 4 0))) ; Z5 + (define (pace/easy) (speed (pace 7 32) (pace 5 7))) ; Z1 and Z2 (define (wk-daniel-q3) (define wk (new fit-workout-file% [name "daniel-q3"] [sport 1])) ((workout (step (minutes 20) (hr/warmup) warmup) (repeat 4 ; times (step (kms 1.2) (pace/hard) active) (step (minutes 4) (no-target) recover)) (step (lap-button) (pace/easy) cooldown)) wk) (send wk get-fit-data)) (wr "daniel.q1.fit" (wk-daniel-q1)) ; write binary data to file Is this a DSL? Its all just objects, functions and function applications supported by some library code. I could write a "#lang workout" with some macros to hide the actual mechanism to make it look more "magic", but I don't see a value in doing that. Best Regards, Alex. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
> On Aug 23, 2017, at 9:49 PM, Alex Harsanyiwrote: > > As someone who managed to write a 3 like Racket application without using > macros, I think they are overrated for application development. Macros are a > powerful and necessary feature for designing or extending a language, but > most people are better served by just using existing, well documented > languages. > > I think Racket is a really good language and can be directly used to write > useful applications. Yet new users are encouraged to start using the most > difficult to understand feature of Racket for their simplest of projects. Yes, Racket is a good language. But let me point you to the blog of a reflective developer, and I consider reflective developers the best of their kind: https://medium.com/@daveford/80-of-my-coding-is-doing-this-or-why-templates-are-dead-b640fc149e22 This write-up is completely unrelated to Racket, but like many others out there, this developer has recognized an essential idea that is emerging in the world of sw dev: problems are best solved on their own terms and that is best done with a multitude of languages — but all these languages must live in the same ecosystem so that it is easy to glue the problem-specific components together. This, in essence, is also the Racket manifesto (http://www.ccs.neu.edu/home/matthias/manifesto/) also available as a PDF article for CACM (http://www.ccs.neu.edu/home/matthias/Tmp/cacm.pdf preferred version). If you would like to see a concrete example, fully worked out, see the ICFP paper on constructing a domain-specific language for scripting the production of videos (say RacketCon presentations): https://www2.ccs.neu.edu/racket/pubs/#icfp17-dnff At the surface, this could be done as a piece of two modules: the surface language (boring) and the run-time library that connects to existing NLVE systems. But as it turns out, if you truly take the slogan seriously, you can easily see how we build this application as a composition of EIGHT (8) DSLs, three used at the surface (Video, Typed Video, and Docu Video) and five below, inside the application. Like Neil, I don’t have any good metric other than “lines of code eliminated/never written”. Based on my personal experience, I find uses for small DSLs or at least bundles of macros everywhere. My most recent example is the construction of a test suite for a distributed board game project. I noticed that I was writing a lot of variations of setup/test/tear-down that were reasonably compact (say 10-15 lines per unit test) but hardly readable. So I rewrote it with a DSL that allowed me to articulate each test as a description of a game scenario. I demoed it to my class, made up of students who do not know Racket. I showed the test suite, I explained the cases for a particularly difficult aspect, and a student spotted a missing corner case. The class was able to dictate the missing test case to me — and of course the code broke. (It was also fixable in about 2 minutes.) If I had demoed the rackunit cases, they would not have been able to formulate the test case — because they simply don’t know (enough) Racket. Time to think — Matthias -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
On Wed, Aug 23, 2017 at 8:49 PM, Alex Harsanyiwrote: > > I think Racket is a really good language and can be directly used to write > useful applications. Yet new users are encouraged to start using the most > difficult to understand feature of Racket for their simplest of projects. > At the risk of going off topic, I would not consider macros the most difficult to understand feature of Racket (especially given the competition from continuations, various concurrency and parallelism constructs, namespaces and eval, inspectors ...). I found syntax-rules style macros a fairly easy step from the style of reasoning about evaluation by substitution of expressions encouraged by HtDP. And syntax-parse makes it easy to address robustness concerns. > > `prefix-in` is an old kludge for an old idea that, AFAIK, is no longer > > considered as good an idea as it used to be. I don't object to prefix-in sometimes, but I would not recommend writing modules in the style of parser-tools/lex-sre (which re-defines things like +) or those documented under http://docs.racket-lang.org/web-server-internal/dispatchers.html (which each export a function named make, even though you will almost always want the make function from more than one such module, making them virtually unusable without prefix-in or rename-in). -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
As someone who managed to write a 3 like Racket application without using macros, I think they are overrated for application development. Macros are a powerful and necessary feature for designing or extending a language, but most people are better served by just using existing, well documented languages. DSLs/minilanguages are, like, kinda a big deal. And Racket has perhaps the best support for them. I think it should be normal for a Racketeer to spend some time getting comfortable with DSLs/minilanguages, so that they can start to recognize when a DSL/minilanguage is a big win. Regarding macros, syntax transformation happens to often be a great way to implement DSLs/minilanguages efficiently in Racket. Shifting computation to compile phase is not the only use of macros, but it's relevant here. I and many other people speak loosely about relative merits of different programming practices, but we don't actually have great metrics for most of that. Lines-of-code (SLOC) metrics, for example, are most useful for saying things like "We refactored, with judicious use of macros and other accepted programming practices, and incidentally cut the million lines down to 200K." and "A hundred million lines of code?! I don't think we can QA that in 3 months." Despite poor metrics, I'm happy to occasionally and generously share my own opinions, and to sniff dismissively at other people's opinions, in the time-honored tradition of programming language forums elsewhere. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
On Thursday, August 24, 2017 at 8:59:26 AM UTC+8, Neil Van Dyke wrote: > h...@oorg wrote on 08/23/2017 06:56 PM: > > > Wouldn't making a DSL be overkill? > > No. In Racket, a DSL (aka minilanguage, syntax extensions, or macros) > can be a very small implementation effort that does exactly what one > wants, in a very maintainable way. As someone who managed to write a 3 like Racket application without using macros, I think they are overrated for application development. Macros are a powerful and necessary feature for designing or extending a language, but most people are better served by just using existing, well documented languages. I think Racket is a really good language and can be directly used to write useful applications. Yet new users are encouraged to start using the most difficult to understand feature of Racket for their simplest of projects. > > Isn't this the sort of thing that should be handled by `prefix-in`? > > `prefix-in` is an old kludge for an old idea that, AFAIK, is no longer > considered as good an idea as it used to be. Do you have any references for this statement? I personally prefer short function names that I can prefix as needed versus littering my code with "author-package-foo" function calls. Is 'prefix-in' a deprecated feature? Best Regards, Alex. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
hiph...@openmailbox.org wrote on 08/23/2017 06:56 PM: Wouldn't making a DSL be overkill? No. In Racket, a DSL (aka minilanguage, syntax extensions, or macros) can be a very small implementation effort that does exactly what one wants, in a very maintainable way. Also, I don't have a choice in the matter how the API data is stored, a hash table is what I receive. You're already running contrived Racket code to generate the hash syntax that you paste into the source file. So you can alternatively paste slightly different contrived syntax, if that gives you an advantage. (Initially, because you happened to paste a Racket hash syntax into that file, you were making your life a lot harder than it needed to be.) The API is only a part of the library, there is also the "client" (connecting to a Neovim instance) and the Racket "host" (allowing Neovim plugins in Racket). I might later re-export the bindings from `nvim/api` through `nvim`, I haven't decided on that yet. This is getting into reuse ecology questions. For now, you might just ask yourself whether this all needs to be in one package. And, if multiple packages, just use the respective package name as the reusable `require` name. Isn't this the sort of thing that should be handled by `prefix-in`? `prefix-in` is an old kludge for an old idea that, AFAIK, is no longer considered as good an idea as it used to be. I recommend trying to make usually-unique identifiers like I said, and save the generic terms for custom `#lang`. The hash table comes from Neovim. I can either send an RPC request (using this library) or run `nvim --api-info` and read from Neovim's standard output. I'm sure you have your reasons for wanting to compile-in what Neovim seems to want to be dynamic info. Such as startup performance, or the ability to later add annotations for semantics missing in the API encoding that Neovim emits. Eventually, perhaps you'll want your Racket API interface to check at runtime against the Neovim process what API it supports, and perhaps enable/disable/change bits of your Racket API interface. You might end up adding annotations to your DSL, or paste multiple versions of the Neovim APIs into that one file, and tweak your DSL's syntax transformers to generate more sophisticated code. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
Thank you all for your answers, I think I got it right this time, but I would still appreciate feedback: https://gitlab.com/HiPhish/neovim.rkt/blob/master/nvim/api.rkt I think what was confusing me was that I was thinking of Racket macros like Common Lisp macros. Instead of trying to build a list that will be the resulting S-expression I needed to build syntax objects. > Neil Van Dyke wrote > If you define a kind of domain-specific language (DSL) syntax > extension in Racket for your Neovim API, your specification might then > look like this (with the "..." filled in): Wouldn't making a DSL be overkill? Also, I don't have a choice in the matter how the API data is stored, a hash table is what I receive. I do not get the decide what the API is myself. > BTW, consider making the `require` name be simply `neovim` or `nvim`, > not `neovim/api` or `nvim/api`. Or call the package `neovim-api`. The API is only a part of the library, there is also the "client" (connecting to a Neovim instance) and the Racket "host" (allowing Neovim plugins in Racket). I might later re-export the bindings from `nvim/api` through `nvim`, I haven't decided on that yet. > Also BTW, consider including the string "neovim" or "nvim" in the > names of all provided identifiers of your API package, such as > `neovim-command` instead of `command`. Isn't this the sort of thing that should be handled by `prefix-in`? The Common Lisp client prefixes `nvim:` https://github.com/adolenc/cl-neovim/#neovims-api https://github.com/adolenc/cl-neovim/blob/master/src/package.lisp#L26 > Philip McGrath wrote > I guess my first question would be where does the hash table in > nvim/api/specification.rkt come from, where else is it used, and is it > necessary for the format to be what it currently is. The hash table comes from Neovim. I can either send an RPC request (using this library) or run `nvim --api-info` and read from Neovim's standard output. The result is in the MessagePack format; MessagePack is similar to JSON, except it's binary instead of text-based. http://msgpack.org/ I wrote my own MessagePack library, and since the MessagePack standard does not promise that keys of dictionaries need to be strings, only an "object" I decided to unpack keys the way they are. I also use vectors when unpacking MessagePack arrays because vectors are closer to what arrays are than a linked list. > Ryan Culpepper wrote > IIUC, you are doing argument/result checking and conversion at run > time. No, I want to do everything at compile time. Your second code example is what helped me to get it working, although I still don't quite understand what `syntax-local-introduce` does and what the `#'here` syntax object is supposed to be (I guess just some arbitrary syntax object that's define right "here"). I'm not concerned with runtime type checks for now, I'll eventually port the library to Typed Racket, then I'll just add the type annotations above the function definition. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
On 08/22/2017 05:29 PM, hiph...@openmailbox.org wrote: Hello, I am writing a Racket library which will make it possible to control the Neovim text editor using Racket. People will be able to use Racket to control Neovim, as well as write plugins for Neovim in Racket. https://gitlab.com/HiPhish/neovim.rkt So far it looks good, but I am stuck on macros. There is a hash table which serves as a specification for which functions to generate, it is stored in the file 'nvim/api/specification.rkt'. This table has the key "functions" which contains a vector of more hash tables. I need this information to generate function definitions for users to be able to call Neovim procedures from Racket. So instead of writing something like (api-call "nvim_command" '#("echo 'hello world'")) users should be able to write (require nvim/api) (command "echo 'hello world'") For this I need to loop over the functions vector like this: (define functions (hash-ref api-info "functions")) (for ([function (in-vector functions)]) (define name (hash-ref function "name")) (defien params (hash-ref function "parameters")) `(define (,(string->symbol name) ,@params) (api-call ,name (vector ,@params Reality is a bit more complicated because the parameters are not a list but a vector of vectors, but that's besides the point. The question is: how do I do this? A regular for-loop at runtime will not work, and wrapping this in begin-for-syntax doesn't produce actual module-level definitions. I tried doing it with a macro: (define-syntax (api->func-def stx) (syntax-case stx () [(_ api-name api-params) (with-syntax ([name (datum->syntax stx (string->symbol (function-name (eval (syntax->datum #'api-name)] [arg-list (datum->syntax stx (vector->list (vector-map string->symbol (eval (syntax->datum #'api-params)]) #`(define (name #,@#'arg-list) (api-call api-name (vector #,@#'arg-list])) This *seems* to generate the proper definition, although I'm not really sure. But how can I write the loop now so that it covers all function definitions? I don't need to re-use the macro, I only need it once, so if there was an easier solution like my for-loop above that does it in place it would be even better. Using `eval` is almost always the wrong (or at least suboptimal) solution unless the problem is "I need to evaluate some code supplied in text form by someone else". You need the names of the functions you want to define at compile time, because Racket requires bindings to be settled at compile time. IIUC, you are doing argument/result checking and conversion at run time. So, assuming you want to keep the information in a single hash table in a single module, you need to require that module once for-syntax and once normally. Here's an example solution to a simplified version of the problem. I've simplified the specification to just the function name and its argument types: ;; file "api-spec.rkt" #lang racket/base (provide functions) ;; A Type is (U 'String 'Number) ;; functions : (Listof (List Symbol (Listof Type))) ;; List of function names and types of arguments. (define functions '((f (String String)) (g (Number String And here's the module that uses that information to define adapter functions: ;; file "api.rkt" #lang racket/base (require (for-syntax racket/base)) ;; Need api-spec at run time to create adapter (require "api-spec.rkt") ;; type->predicate : Type -> (Any -> Boolean) (define (type->predicate type) (case type [(String) string?] [(Number) number?])) ;; make-adapter : Symbol -> Function (define (make-adapter function-name) (define arg-types (cond [(assq function-name functions) => cadr] [else (error 'make-adapter "unknown: ~s" function-name)])) (define arg-preds (map type->predicate arg-types)) (define (wrapper . args) (for ([arg (in-list args)] [pred (in-list arg-preds)] [type (in-list arg-types)]) (unless (pred arg) (error function-name "expected ~a, got: ~e" type arg))) (printf "called ~s on ~v\n" function-name args)) (procedure-reduce-arity wrapper (length arg-types))) ;; Need api-spec at compile time for names to bind (require (for-syntax "api-spec.rkt")) (define-syntax (define-the-functions stx) (syntax-case stx () [(define-all-functions) (with-syntax ([(function-id ...) (for/list ([entry (in-list functions)]) (syntax-local-introduce (datum->syntax #'here (car entry]) #'(begin (define function-id (make-adapter 'function-id)) ... (provide function-id
Re: [racket-users] Generate function defintions at compile time
I guess my first question would be where does the hash table in nvim/api/specification.rkt come from, where else is it used, and is it necessary for the format to be what it currently is. For example, the first thing that jumped out at me is that you're using strings for all the hash keys rather than symbols, which prevents you from using a (faster) hasheq. Also, it is strange to me that functions is a vector and not a list. But it would probably make even more sense to use structs for many of these things, unless it needs to be `read`-able or convertible to json or something. -Philip On Tue, Aug 22, 2017 at 5:06 PM, Neil Van Dykewrote: > hiph...@openmailbox.org wrote on 08/22/2017 05:29 PM: > >> So far it looks good, but I am stuck on macros. There is a hash table >> which serves as a specification for which functions to generate, it is >> stored in the file 'nvim/api/specification.rkt'. This table has the key" >> functions" which contains a vector of more hash tables. >> > > You *can* go from hashes at syntax expansion time to syntax, but, in this > case, I think there are ways that are more idiomatic and (once you're > comfortable with syntax extension) easier... > > If you define a kind of domain-specific language (DSL) syntax extension in > Racket for your Neovim API, your specification might then look like this > (with the "..." filled in): > > (define-and-provide-neovim-api > (version ...) > (error-types ...) > (types ...) > (functions ...) > (ui-events ...)) > > Or: > > (define-and-provide-neovim-api > #:version ... > #:error-types ... > #:types ...) > #:functions ... > #:ui-events ...) > > Then you implement your `define-and-provide-neovim-api` syntax > transformer using `syntax-case` or `syntax-parse`. (When you're > implementing this, it sometimes (not always) helps to type an example use > of your syntax, then type an example of what syntax you would like that to > expand to, and then rework those two examples into your `syntax-case` or > `syntax-parse` form.) > > Or, a somewhat different way is to have separate definition forms in > Racket for each element of the API, such as: > > (define neovim-foo (neovim-api-lambda ...)) > (provide neovim-foo) > > Or: > > (define-and-provide-neovim-procedure neovim-foo ...) > > BTW, consider making the `require` name be simply `neovim` or `nvim`, not > `neovim/api` or `nvim/api`. Or call the package `neovim-api`. > > Also BTW, consider including the string "neovim" or "nvim" in the names of > all provided identifiers of your API package, such as `neovim-command` > instead of `command`. (For example, I included "roomba" in every name in " > http://www.neilvandyke.org/racket/roomba/;.) This is not a rule, just > something to consider. Personally, I would probably make it > `neovim-command` in the API library that can be used from `#lang racket`, > and then, someday, I have the option of making a `#lang neovim` that (among > doing other things) provides that procedure simply as `command` rather than > `neovim-command`. > > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Generate function defintions at compile time
hiph...@openmailbox.org wrote on 08/22/2017 05:29 PM: So far it looks good, but I am stuck on macros. There is a hash table which serves as a specification for which functions to generate, it is stored in the file 'nvim/api/specification.rkt'. This table has the key" functions" which contains a vector of more hash tables. You *can* go from hashes at syntax expansion time to syntax, but, in this case, I think there are ways that are more idiomatic and (once you're comfortable with syntax extension) easier... If you define a kind of domain-specific language (DSL) syntax extension in Racket for your Neovim API, your specification might then look like this (with the "..." filled in): (define-and-provide-neovim-api (version ...) (error-types ...) (types ...) (functions ...) (ui-events ...)) Or: (define-and-provide-neovim-api #:version ... #:error-types ... #:types ...) #:functions ... #:ui-events ...) Then you implement your `define-and-provide-neovim-api` syntax transformer using `syntax-case` or `syntax-parse`. (When you're implementing this, it sometimes (not always) helps to type an example use of your syntax, then type an example of what syntax you would like that to expand to, and then rework those two examples into your `syntax-case` or `syntax-parse` form.) Or, a somewhat different way is to have separate definition forms in Racket for each element of the API, such as: (define neovim-foo (neovim-api-lambda ...)) (provide neovim-foo) Or: (define-and-provide-neovim-procedure neovim-foo ...) BTW, consider making the `require` name be simply `neovim` or `nvim`, not `neovim/api` or `nvim/api`. Or call the package `neovim-api`. Also BTW, consider including the string "neovim" or "nvim" in the names of all provided identifiers of your API package, such as `neovim-command` instead of `command`. (For example, I included "roomba" in every name in "http://www.neilvandyke.org/racket/roomba/;.) This is not a rule, just something to consider. Personally, I would probably make it `neovim-command` in the API library that can be used from `#lang racket`, and then, someday, I have the option of making a `#lang neovim` that (among doing other things) provides that procedure simply as `command` rather than `neovim-command`. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.