From eb4cb683ed09e899a94d6f89fb5a96b048153c3c Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Sat, 18 Jan 2025 20:49:34 -0700 Subject: [PATCH 1/4] doc: crosslink to qi/list docs --- qi-doc/scribblings/field-guide.scrbl | 2 +- qi-doc/scribblings/qi.scrbl | 2 +- qi-doc/scribblings/using-qi.scrbl | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/qi-doc/scribblings/field-guide.scrbl b/qi-doc/scribblings/field-guide.scrbl index 8c98741c4..6be4be31d 100644 --- a/qi-doc/scribblings/field-guide.scrbl +++ b/qi-doc/scribblings/field-guide.scrbl @@ -308,7 +308,7 @@ Qi aims to produce good error messages that convey what the problem is and clear @bold{Meaning}: The interpreter attempted to apply a function to arguments but found that an argument was not of the expected type. -@bold{Common example}: Using @racket[map] or @racket[filter] without first @racket[(require qi/list)]. The built-in Racket versions are @emph{functions} that expect the input list argument at a specific position (i.e., on the right), whereas the Qi versions are @emph{macros} that are invariant to threading direction and expect precisely one input -- the list itself. +@bold{Common example}: Using @racket[map] or @racket[filter] without first @racket[(require qi/list)]. The built-in Racket versions are @emph{functions} that expect the input list argument at a specific position (i.e., on the right), whereas @seclink["List_Operations"]{the Qi versions} are @emph{macros} that are invariant to threading direction and expect precisely one input -- the list itself. @bold{Common example}: Using a nested flow (such as a @racket[tee] junction or an @racket[effect]) within a right-threading flow and assuming that the input arguments would be passed on the right. At the moment, Qi does not propagate the threading direction to nested clauses. You could either use a fresh right threading form or indicate the argument positions explicitly in the nested flow using an @seclink["Templates_and_Partial_Application"]{argument template}. diff --git a/qi-doc/scribblings/qi.scrbl b/qi-doc/scribblings/qi.scrbl index b59dd4608..055e1d70b 100644 --- a/qi-doc/scribblings/qi.scrbl +++ b/qi-doc/scribblings/qi.scrbl @@ -32,7 +32,7 @@ Start by @seclink["Using_These_Docs"]{getting your bearings}. For an overview of @section{Using These Docs} -@secref["Introduction_and_Usage"] provides a high-level overview and includes installation and setup instructions. Learn the language by going through the @secref["Tutorial"], and read @secref["When_Should_I_Use_Qi_"] for examples illustrating its use. The many ways in which Qi may be used from the host language (e.g. Racket), as well as the ways in which Qi may be used in tandem with other DSLs, are described in @secref["Language_Interface"]. The various built-in forms of the language are documented in @secref["Qi_Forms"], while @secref["Qi_Macros"] covers using macros to extend the language by adding new features or implementing new DSLs. @secref["Principles_of_Qi"] provides a theoretical foundation to develop a sound intuition for Qi, and the @secref["Field_Guide"] contains practical advice. @secref["Flowing_with_the_Flow"] contains recommendations on editor configuration to help you to write Qi effectively. +@secref["Introduction_and_Usage"] provides a high-level overview and includes installation and setup instructions. Learn the language by going through the @secref["Tutorial"], and read @secref["When_Should_I_Use_Qi_"] for examples illustrating its use. The many ways in which Qi may be used from the host language (e.g. Racket), as well as the ways in which Qi may be used in tandem with other DSLs, are described in @secref["Language_Interface"]. The various built-in forms of the language are documented in @secref["Qi_Forms"], while @secref["Qi_Macros"] covers using macros to extend the language by adding new features or implementing new DSLs, and @secref["List_Operations"] describes forms for expressing optimized list-oriented operations. @secref["Principles_of_Qi"] provides a theoretical foundation to develop a sound intuition for Qi, and the @secref["Field_Guide"] contains practical advice. @secref["Flowing_with_the_Flow"] contains recommendations on editor configuration to help you to write Qi effectively. This site hosts @emph{user} documentation. If you are interested in contributing to Qi development you may be interested in the @emph{developer} documentation at the @hyperlink["https://github.com/drym-org/qi/wiki"]{Qi Wiki}. The wiki is also your one-stop shop for keeping up with planned events in the Qi community. diff --git a/qi-doc/scribblings/using-qi.scrbl b/qi-doc/scribblings/using-qi.scrbl index baa6384cc..5ba08e480 100644 --- a/qi-doc/scribblings/using-qi.scrbl +++ b/qi-doc/scribblings/using-qi.scrbl @@ -208,6 +208,8 @@ The equivalent Qi flow is: (~> (filter odd?) (map sqr))) } +Note that @racket[filter] and @racket[map] here are the ones from @racketmodname[qi/list]. + Here, under the hood, each element of the input list is processed one at a time, with both of these functions being invoked on it in sequence, and then the output list is constructed by accumulating these individual results. This ensures that no intermediate lists are constructed along the way and that the input list is traversed just once -- a standard optimization technique called "stream fusion" or "deforestation." The Qi version produces the same result as the Racket code above, but it can be both faster as well as more memory-efficient, especially on large input lists. Note however that if the functions used in @racket[filter] and @racket[map] are not @emph{pure}, that is, if they perform side effects like printing to the screen or writing to a file, then the Qi flow would exhibit a different @seclink["Order_of_Effects"]{order of effects} than the Racket version. @section{Curbing Curries and Losing Lambdas} From a3d4b05dc593e58928caa71ab02d37480f28a36c Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Sat, 18 Jan 2025 20:49:54 -0700 Subject: [PATCH 2/4] doc: move `!` under full syntax instead of core language syntax --- qi-doc/scribblings/forms.scrbl | 1 + qi-doc/scribblings/principles.scrbl | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/qi-doc/scribblings/forms.scrbl b/qi-doc/scribblings/forms.scrbl index 38bf91ba0..be738e7f5 100644 --- a/qi-doc/scribblings/forms.scrbl +++ b/qi-doc/scribblings/forms.scrbl @@ -41,6 +41,7 @@ The full surface syntax of Qi is given below. Note that this expands to a @secli & OR ∥ + ! NOR NAND XNOR diff --git a/qi-doc/scribblings/principles.scrbl b/qi-doc/scribblings/principles.scrbl index b4ec1dfc7..95f180d3a 100644 --- a/qi-doc/scribblings/principles.scrbl +++ b/qi-doc/scribblings/principles.scrbl @@ -163,7 +163,6 @@ Qi flow expressions expand to a small core language which is then @seclink["It_s (or floe ...) (not floe) NOT - ! XOR ground (thread floe ...) From bacb20878454d6892476f1d11dca49313eb9f2dc Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Sat, 18 Jan 2025 21:31:01 -0700 Subject: [PATCH 3/4] document qi's "continuous deployment" development practice --- qi-doc/scribblings/intro.scrbl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/qi-doc/scribblings/intro.scrbl b/qi-doc/scribblings/intro.scrbl index 7a490238f..b2fed0aa7 100644 --- a/qi-doc/scribblings/intro.scrbl +++ b/qi-doc/scribblings/intro.scrbl @@ -69,6 +69,29 @@ Qi is a hosted language on the @hyperlink["https://racket-lang.org/"]{Racket pla Additionally, Qi itself uses few and carefully benchmarked dependencies, so that the load-time overhead of @racket[(require qi)] is minimal. +@subsection{About Qi's Release Practices} + +Qi follows the @hyperlink["http://timothyfitz.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/"]{continuous deployment} model of development. This means that fresh changes are immediately pushed to the main branch of development after they pass a rigorous and comprehensive suite of tests. + +Furthermore, Qi packages on the Racket package index point to this main branch on the source host, so that running @racket[raco pkg install qi] or @racket[raco pkg update qi] will always get the version on the @racket[main] branch, reflecting the latest improvements. + +This doesn't mean that you must use this version, however. The expressiveness of modern version control systems allows us to define diverse versioning protocols directly on the versioning backend to best support diverse usage needs. Towards this end, Qi follows these conventions: + +@itemlist[#:style 'ordered + @item{Each significant new release has a tagged version, which is static and immutable.} + @item{Each legacy release has a "maintenance" branch that will be stable without any backwards incompatible changes or new features, and will be supported with bug fixes as needed.} +] + +Together, these practices decouple development from use, effectively eliminating the problem of backwards compatibility. Specifically, Qi may occasionally change in a way that might traditionally be labeled "backwards-incompatible," but by relying on a version tag with either of the above semantics, such a change would not affect your application unless you are interested in the new features and until such a time as you are ready to upgrade. Thus, it gives users flexibility and stability without compromising the freedom to innovate and remedy past missteps for developers of Qi. + +In case you need to rely on a version with either of the above semantics, we recommend declaring a Git @tech{package source} in your @racket[info.rkt], instead of a Racket @tech{package source}. Like this: + +@codeblock{ + (define deps '("git://github.com/drym-org/qi.git#v5.0")) +} + +Now, traditionally, we may have grown accustomed to depending on a certain version of a package "or newer" (as are the semantics of using a Racket, rather than Git, @tech{package source}), so that we never have to update the dependency specification to get the latest improvements. We believe that this is a fragile convention that simultaneously overburdens development while threatening application stability. It's inadvisable for the same reason that mutability in programs is inadvisable, that is, introducing superfluous coupling and incurring the attendant risks. After all, any introduced bug is technically backwards-incompatible, as, indeed, is the fix for the bug! On the other hand, the branch strategy above supports these semantics to a sensible extent -- that of receiving necessary bug fixes, but not gratuitous "improvements" that may unwittingly break your application, even if they aren't intended to be backwards-incompatible. + @section{Relationship to the Threading Macro} The usual threading macro in @seclink["top" #:indirect? #t #:doc '(lib "scribblings/threading.scrbl")]{Threading Macros} is a purely syntactic transformation that does not make any assumptions about the expressions being threaded through, so that it works out of the box for threading values through both functions as well as macros. On the other hand, Qi is primarily oriented around @emph{functions}, and @tech{flows} are expected to be @seclink["What_is_a_Flow_"]{function-valued}. Threading values through macros using Qi requires special handling. From 84bd92067197edaabff1c926132b8cd682f0304c Mon Sep 17 00:00:00 2001 From: Siddhartha Date: Fri, 24 Jan 2025 09:21:45 -0700 Subject: [PATCH 4/4] incorporate code review for docs on release practices --- qi-doc/scribblings/intro.scrbl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/qi-doc/scribblings/intro.scrbl b/qi-doc/scribblings/intro.scrbl index b2fed0aa7..7d087cd1b 100644 --- a/qi-doc/scribblings/intro.scrbl +++ b/qi-doc/scribblings/intro.scrbl @@ -71,26 +71,26 @@ Qi is a hosted language on the @hyperlink["https://racket-lang.org/"]{Racket pla @subsection{About Qi's Release Practices} -Qi follows the @hyperlink["http://timothyfitz.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/"]{continuous deployment} model of development. This means that fresh changes are immediately pushed to the main branch of development after they pass a rigorous and comprehensive suite of tests. +Qi breaks with traditional Racket package development and occasionally ships breaking changes in a @hyperlink["https://semver.org/"]{SemVer}-style major release. For that reason, in some cases when using Qi as a dependency, it is advisable to pin to a Qi tag using a Git @tech{package source} rather than follow the main "qi" Racket @tech{package source}. Keep reading for details and examples. -Furthermore, Qi packages on the Racket package index point to this main branch on the source host, so that running @racket[raco pkg install qi] or @racket[raco pkg update qi] will always get the version on the @racket[main] branch, reflecting the latest improvements. +Qi follows the @hyperlink["http://timothyfitz.com/2009/02/10/continuous-deployment-at-imvu-doing-the-impossible-fifty-times-a-day/"]{continuous deployment} model of development. This means that fresh changes are pushed to the main branch of development after they pass a rigorous and comprehensive suite of tests and thorough code review. Additionally, Qi packages on the Racket package index point to this main branch on the source host, so that running @racket[raco pkg install qi] or @racket[raco pkg update qi] will always get the version on the @racket[main] branch, reflecting the latest improvements. -This doesn't mean that you must use this version, however. The expressiveness of modern version control systems allows us to define diverse versioning protocols directly on the versioning backend to best support diverse usage needs. Towards this end, Qi follows these conventions: +This doesn't mean that you must use this version, however. The expressiveness of modern version control systems allows us to define diverse versioning protocols directly on the versioning backend (e.g., Git) to best support diverse usage needs. Towards this end, Qi follows these conventions: @itemlist[#:style 'ordered @item{Each significant new release has a tagged version, which is static and immutable.} @item{Each legacy release has a "maintenance" branch that will be stable without any backwards incompatible changes or new features, and will be supported with bug fixes as needed.} ] -Together, these practices decouple development from use, effectively eliminating the problem of backwards compatibility. Specifically, Qi may occasionally change in a way that might traditionally be labeled "backwards-incompatible," but by relying on a version tag with either of the above semantics, such a change would not affect your application unless you are interested in the new features and until such a time as you are ready to upgrade. Thus, it gives users flexibility and stability without compromising the freedom to innovate and remedy past missteps for developers of Qi. +Now, traditionally, we may have grown accustomed to depending on a certain version of a package "or newer" (as are the semantics of using a Racket, rather than Git, @tech{package source}), so that we never have to update the dependency specification to get the latest improvements. We believe that this convention needlessly overburdens development while threatening application stability, requiring us to choose one or the other. -In case you need to rely on a version with either of the above semantics, we recommend declaring a Git @tech{package source} in your @racket[info.rkt], instead of a Racket @tech{package source}. Like this: +But instead, by relying on a version with either of the above semantics, we gain stability and flexibility as users of Qi without compromising the freedom to innovate and remedy past missteps for developers of Qi. This style of dependency can be accomplished by using a Git @tech{package source} in your @racket[info.rkt], instead of a Racket @tech{package source}. Like this: @codeblock{ (define deps '("git://github.com/drym-org/qi.git#v5.0")) } -Now, traditionally, we may have grown accustomed to depending on a certain version of a package "or newer" (as are the semantics of using a Racket, rather than Git, @tech{package source}), so that we never have to update the dependency specification to get the latest improvements. We believe that this is a fragile convention that simultaneously overburdens development while threatening application stability. It's inadvisable for the same reason that mutability in programs is inadvisable, that is, introducing superfluous coupling and incurring the attendant risks. After all, any introduced bug is technically backwards-incompatible, as, indeed, is the fix for the bug! On the other hand, the branch strategy above supports these semantics to a sensible extent -- that of receiving necessary bug fixes, but not gratuitous "improvements" that may unwittingly break your application, even if they aren't intended to be backwards-incompatible. +In addition, as part of each release, backwards incompatibilities are publicly announced and an effort is made to work with dependent package and application developers to ensure compatibility with the latest release, further bridging the gap to Racket's package management practices. Thus, in practice, outside of a production deployment, relying on the Racket @tech{package source} should be fine. @section{Relationship to the Threading Macro}