Skip to content

Commit

Permalink
Merge pull request #179 from drym-org/deforest-all-the-things
Browse files Browse the repository at this point in the history
Deforest All the Things
  • Loading branch information
countvajhula authored Jan 17, 2025
2 parents 442e5e4 + f84dc92 commit d0566bb
Show file tree
Hide file tree
Showing 46 changed files with 2,479 additions and 1,466 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- name: Check Dependencies
run: make check-deps
- name: Run Tests
run: make test
run: make test-all
coverage:
needs: test
runs-on: ubuntu-latest
Expand Down
2 changes: 2 additions & 0 deletions COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
This is free and unencumbered software released into the public domain.
The authors relinquish any copyright claims on this work.
26 changes: 23 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ build-all:
build-standalone-docs:
scribble +m --redirect-main http://pkg-build.racket-lang.org/doc/ --htmls --dest ./docs ./qi-doc/scribblings/qi.scrbl

build-sdk:
raco setup --no-docs --pkgs $(PACKAGE-NAME)-sdk

# Note: Each collection's info.rkt can say what to clean, for example
# (define clean '("compiled" "doc" "doc/<collect>")) to clean
# generated docs, too.
Expand All @@ -113,15 +116,21 @@ clean-sdk:
check-deps:
raco setup --no-docs $(DEPS-FLAGS) $(PACKAGE-NAME)

test-all: test test-probe

# Suitable for both day-to-day dev and CI
# Note: we don't test qi-doc since there aren't any tests there atm
# and it also seems to make things extremely slow to include it.
test:
raco test -exp $(PACKAGE-NAME)-{lib,test,probe}
test: build
raco make -l qi/tests/qi -v
raco test -exp $(PACKAGE-NAME)-{lib,test}

test-flow:
racket -y $(PACKAGE-NAME)-test/tests/flow.rkt

test-list:
racket -y $(PACKAGE-NAME)-test/tests/list.rkt

test-on:
racket -y $(PACKAGE-NAME)-test/tests/on.rkt

Expand Down Expand Up @@ -211,6 +220,17 @@ new-benchmarks:
--dest-name index.html \
report.scrbl

new-benchmarks-preview:
cd qi-sdk/benchmarks/competitive && \
scribble \
++convert svg \
++arg -p \
++arg preview \
--html \
--dest results \
--dest-name index.html \
report.scrbl

benchmark-local:
racket $(PACKAGE-NAME)-sdk/benchmarks/local/report.rkt

Expand All @@ -234,4 +254,4 @@ performance-report:
performance-regression-report:
@racket $(PACKAGE-NAME)-sdk/benchmarks/report.rkt -r $(REF)

.PHONY: help install remove build build-docs build-all clean check-deps test test-flow test-on test-threading test-switch test-definitions test-macro test-util test-expander test-compiler test-probe test-with-errortrace errortrace errortrace-flow errortrace-on errortrace-threading errortrace-switch errortrace-definitions errortrace-macro errortrace-util errortrace-probe docs cover coverage-check coverage-report cover-coveralls profile new-benchmarks benchmark-local benchmark-loading benchmark-selected-forms benchmark-competitive benchmark-nonlocal benchmark performance-report performance-regression-report
.PHONY: help install remove build build-docs build-all clean check-deps test-all test test-flow test-on test-threading test-switch test-definitions test-macro test-util test-expander test-compiler test-probe test-with-errortrace errortrace errortrace-flow errortrace-on errortrace-threading errortrace-switch errortrace-definitions errortrace-macro errortrace-util errortrace-probe docs cover coverage-check coverage-report cover-coveralls profile new-benchmarks new-benchmarks-preview benchmark-local benchmark-loading benchmark-selected-forms benchmark-competitive benchmark-nonlocal benchmark performance-report performance-regression-report
4 changes: 3 additions & 1 deletion qi-doc/scribblings/field-guide.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ Qi aims to produce good error messages that convey what the problem is and clear

@bold{Common example}: Attempting to use a Qi macro in one module without @racketlink[provide]{providing} it from the module where it is defined -- note that Qi macros must be provided as @racket[(provide (for-space qi mac))]. See @secref["Using_Macros" #:doc '(lib "qi/scribblings/qi.scrbl")] for more on this.

@subsubsection{Contract Violation}
@subsubsection{@racket[map]/@racket[filter] Contract Violation}

@codeblock{
; map: contract violation
Expand All @@ -308,6 +308,8 @@ 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 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}.

@subsubsection{Compose: Contract Violation}
Expand Down
115 changes: 111 additions & 4 deletions qi-doc/scribblings/forms.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@require[scribble/manual
scribble-abbrevs/manual
scribble/example
metapict ; technically only used dynamically, but adding here for info deps
"eval.rkt"
@for-label[(only-space-in qi qi)
racket]]
Expand All @@ -14,10 +15,102 @@

@title[#:tag "Qi_Forms"]{The Qi Language}

The core syntax of the Qi language. These forms may be used in any @tech{flow}. Flows may be specified in Racket via the @seclink["Language_Interface"]{language interface}.
The syntax and semantics of the Qi language. Qi @tech{flows} may be described using these forms and @seclink["Embedding_a_Hosted_Language"]{embedded} into Racket using the @seclink["Language_Interface"]{language interface}.

@table-of-contents[]

@section{Syntax}

The syntax of a language is most economically and clearly expressed using a grammar, in the form of "nonterminal" symbols along with production rules expressing the syntax that is entailed in positions marked by those symbols. We may thus take the single starting symbol in such a grammar to formally designate the entire syntax of the language.

The symbol @racket[expr] is typically used in this sense to indicate a Racket nonterminal position in the syntax, i.e., a position that expects a Racket expression. Analogously, we use the identifier @deftech{@racket[floe]} (pronounced "flow-e," for "flow expression") to refer to the Qi nonterminal, i.e., a position expecting Qi syntax.

@tech{floe} is not to be confused with @tech{flow}. The relationship between the two is one of syntax and semantics, that is, the meaning of a @tech{floe} is a @tech{flow}.

The full surface syntax of Qi is given below. Note that this expands to a @seclink["The_Qi_Core_Language"]{smaller core language} before being @seclink["It_s_Languages_All_the_Way_Down"]{compiled to Racket}. It does not include the @seclink["List_Operations"]{list-oriented forms}, which may be added via @racket[(require qi/list)].

@racketgrammar*[
[floe @#,seclink["The_Qi_Core_Language"]{core-form}
macro-form]
[macro-form △
(one-of? expr ...)
(and% floe ...)
(or% floe ...)
AND
&
OR
NOR
NAND
XNOR
any?
all?
none?
inverter
(~> floe ...)
(~>> floe ...)
(thread-right floe ...)
X
crossover
==
(== floe ...)
(==* floe ...)
(relay* floe ...)
-<
(-< floe ...)
count
1>
2>
3>
4>
5>
6>
7>
8>
9>
(bundle (index ...) floe floe)
(when floe floe)
(unless floe floe)
switch
(switch switch-expr ...)
(switch (% floe) switch-expr ...)
(switch (divert floe) switch-expr ...)
(gate floe)
><
(>< floe)
(ε floe floe)
(effect floe floe)
apply
(expr expr ... __ expr ...)
(expr expr ... _ expr ...)
(expr expr ...)
literal
identifier]
[literal boolean
char
string
bytes
number
regexp
byte-regexp
vector-literal
box-literal
prefab-literal
(@#,racket[quote] value)
(@#,racket[quasiquote] value)
(@#,racket[quote-syntax] value)
(@#,racket[syntax] value)]
[expr a-racket-expression]
[index exact-positive-integer?]
[nat exact-nonnegative-integer?]
[switch-expr [floe floe]
[floe (=> floe)]
[else floe]]
[identifier a-racket-identifier]
[value a-racket-value]]

@section{Basic}

@defidform[_]{
Expand Down Expand Up @@ -100,6 +193,20 @@ The core syntax of the Qi language. These forms may be used in any @tech{flow}.
]
}

@deftogether[(
@defform[(lambda expr ...)]
@defform[(λ expr ...)]
)]{
Shorthand for @racket[(esc (lambda ...))].

That is, this lambda is a @emph{Qi} form that expands to a use of @emph{Racket}'s lambda form, providing a shorthand for a common way to describe a flow using Racket.

@examples[
#:eval eval-for-docs
((☯ (λ (x) (+ 2 x))) 3)
]
}

@defform[(clos flo)]{
A @tech{flow} that generates a flow as a value. Any inputs to the @racket[clos] flow are available to @racket[flo] when it is applied to inputs, i.e. it is analogous to a @hyperlink["https://www.gnu.org/software/guile/manual/html_node/Closure.html"]{closure} in Racket.

Expand Down Expand Up @@ -514,9 +621,9 @@ A form of generalized @racket[sieve], passing all the inputs that satisfy each
[(switch maybe-divert-expr switch-expr ...)]
([maybe-divert-expr (divert condition-gate-flow consequent-gate-flow)
(% condition-gate-flow consequent-gate-flow)]
[switch-expr [flow-expr flow-expr]
[flow-expr (=> flow-expr)]
[else flow-expr]])]{
[switch-expr [floe floe]
[floe (=> floe)]
[else floe]])]{
The @tech{flow} analogue of @racket[cond], this is a dispatcher where the condition and consequent expressions are all flows which operate on the switch inputs.

Typically, each of the component flows -- conditions and consequents both -- receives all of the original inputs to the @racket[switch]. This can be changed by using a @racket[divert] clause, which takes two flow arguments, the first of whose outputs go to all of the condition flows, and the second of whose outputs go to all of the consequent flows. This can be useful in cases where multiple values flow, but only some of them are predicated upon, and others (or all of them) inform the actions to be taken. Using @racket[(divert _ _)] is equivalent to not using it. @racket[%] is a symbolic alias for @racket[divert] -- parse it visually not as the percentage sign, but as a convenient way to depict a "floodgate" diverting values down different channels.
Expand Down
Loading

1 comment on commit d0566bb

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'Qi Performance Trends'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 2.

Benchmark suite Current: d0566bb Previous: 442e5e4 Ratio
range-map-car 166 ms 13 ms 12.77
long-functional-pipeline 1690 ms 79 ms 21.39

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.