Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Racket list deforestation #175

Merged

Conversation

dzoep
Copy link
Collaborator

@dzoep dzoep commented Jun 15, 2024

Summary of Changes

  • introduce new bindings for deforested racket/base and racket/list procedures
  • use literal matching on the new bindings in deforestation pass
  • provide the new bindings from qi/list in place of the originals bindings
  • add scribblings for the new bindings with links to original Racket documentation
  • deforested take from racket/list using "state consing"
  • added new tests and fixed some existing to work with the new changes

Public Domain Dedication

  • In contributing, I relinquish any copyright claims on my contribution and freely release it into the public domain in the simple hope that it will provide value.

(Why: The freely released, copyright-free work in this repository represents an investment in a better way of doing things called attribution-based economics. Attribution-based economics is based on the simple idea that we gain more by giving more, not by holding on to things that, truly, we could only create because we, in our turn, received from others. As it turns out, an economic system based on attribution -- where those who give more are more empowered -- is significantly more efficient than capitalism while also being stable and fair (unlike capitalism, on both counts), giving it transformative power to elevate the human condition and address the problems that face us today along with a host of others that have been intractable since the beginning. You can help make this a reality by releasing your work in the same way -- freely into the public domain in the simple hope of providing value. Learn more about attribution-based economics at drym.org, tell your friends, do your part.)

Copy link
Collaborator

@countvajhula countvajhula left a comment

Choose a reason for hiding this comment

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

This is a big PR! It'll take me a few more passes to get through it, but we have enough to discuss for now.

[(_ [op (f ...) g ...] rest ...) (op f ... (inline-compose1 rest ...) g ...)]
))

(define-syntax inline-consing
Copy link
Collaborator

Choose a reason for hiding this comment

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

An explanatory comment would be great (similar to above)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do.

range

filter
map
Copy link
Collaborator

Choose a reason for hiding this comment

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

Now that we are providing Qi bindings, for higher order functions I believe the f position(s) should be floe rather than expr. That is:

Not:

(~> (filter (λ (v) (= 0 (remainder v 3)))) (map (λ (v) (+ v 2))))

But instead:

(~> (filter (~> (remainder 3) (= 0))) (map (+ 2)))

Simple uses of function identifiers would be the same as for uses of Racket's map and filter

(~> (filter odd?) (map sqr))

But if a (Racket) lambda is desired it would need to be explicitly escaped:

(~> (map (esc (λ (v) (+ v 2)))))

"passes.rkt")
"../strategy.rkt"
"../private/form-property.rkt")
"../passes.rkt")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Moving the passes under compiler/ 👌

@@ -0,0 +1,298 @@
#lang racket/base
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice job separating out the matching/validation from the production. It should help us when we get to the point of moving the matching into the expander.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Producers

(define-syntax-class fsp-range
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we are going to use abbreviated names, the abbreviations should be clarified in comments, e.g. something like "In these syntax classes, fsp stands for fusable stream producer. These classes match functions that produce a sequence of values, such as range, and they annotate the syntax with attributes that will be used in the compiler to apply optimizations."

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do.


;; Performs deforestation rewrite on the whole syntax tree.
(define-and-register-deforest-pass (deforest-pass ops ctx)
(syntax-parse (reverse ops)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would prefer using define-and-register-pass directly here rather than use a macro we don't anticipate another need for. To keep it modular, this (syntax-parse ...) bit could be moved into a locally-defined function.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

See above - this one will be also used in the named-let implementation in the (near) future.

'take ctx
#f
src
) '()))
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: parentheses are weird here. Would recommend keeping to Racket's conventions of not having dangling parens here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will do in the integration branch as a new PR streamlining the comments across the compiler.

qi-lib/flow/core/compiler/deforest/cps.rkt Outdated Show resolved Hide resolved
qi-lib/flow/core/compiler/deforest/cps.rkt Outdated Show resolved Hide resolved
qi-lib/list.rkt Show resolved Hide resolved
@countvajhula
Copy link
Collaborator

countvajhula commented Jun 28, 2024

The more I think about it, I do not like providing bindings from Qi that have Racket syntax (which we discussed in today's meeting, in a separate qi/deforest). I understand that it provides an easy transition from Racket-syntaxed list operations to Qi-syntaxed list operations over the course of development of deforestation, so it could be an acceptable compromise. I'd love to get more thoughts on it in the form of code review.

My preference would be to work out the proper interface together as part of merging this PR, and in addition, provide only Qi-syntaxed bindings from Qi libraries like qi/list. It's OK if it doesn't include all the bindings in racket/list out of the gate, since users could require them and use them as partial application forms, without deforestation, which is anyway already the case. I feel the majority of interfaces in racket/list are not widely used so I'm not sure it is a top priority to be comprehensive on day one.

In any case, having a clean interface now would unblock the deforestation efforts in earnest and I wouldn't be paranoid and watching over your shoulder @dzoep . Until then, I hesitate 😅

Copy link
Collaborator

@benknoble benknoble left a comment

Choose a reason for hiding this comment

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

Apologies in advance for this absolutely massive review; I did this offline over a week ago by annotating the results of git switch racket-list-deforestation && git format-patch --cover-letter main -o patches, so it built up. I did walk commit by commit, so you might want to do the same to get context on my review comments.

  • I get a compilation error in qi-sdk when building this branch with raco setup -l qi:

    raco setup: error: during making for <pkgs>/qi-sdk/benchmarks/nonlocal/qi
    raco setup:   qi-sdk/benchmarks/nonlocal/qi/main.rkt:23:9: module: identifier already required
    raco setup:     at: range
    raco setup:     in: qi/list
    raco setup:     compiling: <pkgs>/qi-sdk/benchmarks/nonlocal/qi/main.rkt
    
  • FHM tests pass (haven't tried actually running it yet)

  • Second Sid's comments about standard Racket parentheses: all closers belong on
    the same line. I would also prefer to see idiomatic square brackets (raco fmt can help with this, but I don't always agree with the way it shoves
    things onto one line when I want the separation). This occurs in more places
    than I think I saw fixed.

  • On a related note, I'm not a fan of long (begin-… blocks: it can be hard to
    eyeball things when the (begin is way off the screen. I've suggested one or
    two ways to try to slim them down, but I don't know if you already fixed one
    of them.

  • Commit hygiene: I'd prefer each commit to make sense on its own (and ideally
    build + pass tests), so I've left targeted comments about what should be
    squashed or fixed up where, etc. It's probably going to be challenging at this
    stage; you might want to create a v2 branch and slowly cherry-pick commits,
    fix them up, etc., instead of trying a complicated interactive rebase. (It's
    the same effect and will have all the same conflicts; it might be easier to
    keep track of what's going on that way.) An extreme alternative option would be to squash-merge this PR, at which point I would beseech you to write a solid message describing the whole PR as if it were a single commit so that Sid (or whoever merges) can paste that in (GitHub's "default squash message" is worse that useless).

qi-lib/flow/core/deforest.rkt Outdated Show resolved Hide resolved
qi-lib/flow/core/deforest.rkt Outdated Show resolved Hide resolved
qi-lib/flow/core/deforest.rkt Outdated Show resolved Hide resolved
qi-lib/flow/core/deforest.rkt Outdated Show resolved Hide resolved
qi-lib/flow/core/deforest.rkt Show resolved Hide resolved
qi-lib/flow/core/compiler/deforest/cps.rkt Show resolved Hide resolved
qi-lib/flow/core/compiler/deforest/fusion.rkt Show resolved Hide resolved
qi-lib/flow/core/compiler/deforest/fusion.rkt Show resolved Hide resolved
qi-lib/flow/core/compiler/deforest/syntax.rkt Show resolved Hide resolved
qi-lib/flow/core/compiler/deforest/fusion.rkt Outdated Show resolved Hide resolved
Deforest all variants of cad*r:

- car
- cadr
- caddr
- cadddr
- caddddr
- cadddddr

Deforest (using the same underlying implementation) list-ref as well.
- split syntax matching from syntax production
- improve naming of syntax classes
- remove unused template variables
@dzoep dzoep force-pushed the racket-list-deforestation branch from ce0bc49 to 121b212 Compare July 26, 2024 07:52
@benknoble
Copy link
Collaborator

I won't have time ahead of today's meeting, but I do intend to resolve any of my comments that are no longer needed. (If anyone else happens to go through them, that's fine too.)

@dzoep dzoep changed the base branch from main to deforest-list-operations July 26, 2024 18:43
dzoep and others added 15 commits July 27, 2024 23:17
- preliminary splitting of the compiler into separate modules for separate passes
- update tests to reflect new paths
- rename compiler "passes" subdirectory to "compiler"
- strip the passes modules file name pass- prefix
Towards addressing feedback on discord from @dented42
- scribblings for qi/list module
- scribble the new literals for matching in deforestation pass
- ensure for-label bindings in the generated documentation
- new bindings.rkt module
…ler meeting on 2024-06-21.

- add detailed explanation for inline-consing syntax
- use Racket's conventions for parentheses
- add description of fsp-, fst-, and fsc- prefixes
- move define-and-register-deforest-pass and related to separate module, add comments
@dzoep dzoep force-pushed the racket-list-deforestation branch from 121b212 to 016ab41 Compare July 27, 2024 21:21
@benknoble
Copy link
Collaborator

I've marked many comments resolved, but left open the ones that aren't addressed and that I think should still be (or at least should be considered).

I also still get an error in qi-sdk when trying to build locally.

@benknoble
Copy link
Collaborator

Also, it looks like there are some whitespace oddities. For example, try using the git-jump script from Git's contrib directory with this branch checked out:

git jump ws main..

Here's the resulting fix list:

qi-doc/scribblings/list-operations.scrbl:4: space before tab in indent.
+	 	    racket/base)]
qi-doc/scribblings/list-operations.scrbl:94: space before tab in indent.
+ 	   ((list-ref (lst pair?) (pos exact-nonnegative-integer?)) any/c))]{
qi-doc/scribblings/list-operations.scrbl:117: new blank line at EOF.
qi-lib/flow/core/compiler/1000-qi0.rkt:16: trailing whitespace.
+  
qi-lib/flow/core/compiler/2000-bindings.rkt:73: new blank line at EOF.
qi-lib/flow/core/compiler/deforest/bindings.rkt:20: trailing whitespace.
+  

@benknoble
Copy link
Collaborator

For the conflicts, I started the merge and then ran git log --oneline --left-right --merge -p to get the following, which shows that resolving the conflicts is probably straightforward:

< 06644b9 Fix tests of qi/list - use the new bindings.
diff --git a/qi-test/tests/compiler/rules/full-cycle.rkt b/qi-test/tests/compiler/rules/full-cycle.rkt
index 3b4535b..5aaca6b 100644
--- a/qi-test/tests/compiler/rules/full-cycle.rkt
+++ b/qi-test/tests/compiler/rules/full-cycle.rkt
@@ -11,6 +11,7 @@
          rackunit/text-ui
          syntax/macro-testing
          qi/flow/core/compiler/0100-deforest
+         qi/list
          "private/deforest-util.rkt"
          (submod qi/flow/extended/expander invoke))
 
< ed36927 Improve directory and module naming
diff --git a/qi-test/tests/compiler/rules/full-cycle.rkt b/qi-test/tests/compiler/rules/full-cycle.rkt
index 5b16f09..3b4535b 100644
--- a/qi-test/tests/compiler/rules/full-cycle.rkt
+++ b/qi-test/tests/compiler/rules/full-cycle.rkt
@@ -10,7 +10,7 @@
          rackunit
          rackunit/text-ui
          syntax/macro-testing
-         qi/flow/core/passes/pass-0100-deforest
+         qi/flow/core/compiler/0100-deforest
          "private/deforest-util.rkt"
          (submod qi/flow/extended/expander invoke))
 
< 8383bcf Split compiler passes into separate modules.
diff --git a/qi-test/tests/compiler/rules/full-cycle.rkt b/qi-test/tests/compiler/rules/full-cycle.rkt
index 52d21a9..5b16f09 100644
--- a/qi-test/tests/compiler/rules/full-cycle.rkt
+++ b/qi-test/tests/compiler/rules/full-cycle.rkt
@@ -10,7 +10,7 @@
          rackunit
          rackunit/text-ui
          syntax/macro-testing
-         qi/flow/core/deforest
+         qi/flow/core/passes/pass-0100-deforest
          "private/deforest-util.rkt"
          (submod qi/flow/extended/expander invoke))
 
> 515122f More direct "full cycle" compiler test macro
diff --git a/qi-test/tests/compiler/rules/full-cycle.rkt b/qi-test/tests/compiler/rules/full-cycle.rkt
index 52d21a9..e7e1749 100644
--- a/qi-test/tests/compiler/rules/full-cycle.rkt
+++ b/qi-test/tests/compiler/rules/full-cycle.rkt
@@ -11,22 +11,15 @@
          rackunit/text-ui
          syntax/macro-testing
          qi/flow/core/deforest
+         qi/flow/core/compiler
          "private/deforest-util.rkt"
          (submod qi/flow/extended/expander invoke))
 
 (begin-for-syntax
-  (require syntax/parse/define
-           (for-template qi/flow/core/compiler)
-           (for-syntax racket/base))
-
-  ;; A macro that accepts surface syntax, expands it, and then applies the
-  ;; indicated optimization passes.
-  (define-syntax-parser test-compile~>
-    [(_ stx)
-     #'(expand-flow stx)]
-    [(_ stx pass ... passN)
-     #'(passN
-        (test-compile~> stx pass ...))]))
+  ;; A function that expands and compiles surface syntax
+  (define (qi-compile stx)
+    (compile-flow
+     (expand-flow stx))))
 
 
 (define tests
@@ -39,9 +32,8 @@ (define tests
     (test-true "normalize → deforest"
                (deforested?
                  (phase1-eval
-                  (test-compile~> #'(~>> (filter odd?) values (map sqr))
-                                  normalize-pass
-                                  deforest-pass)))))))
+                  (qi-compile
+                   #'(~>> (filter odd?) values (map sqr)))))))))
 
 (module+ main
   (void

In fact, it's probably a good idea to try rebasing on top of the latest main (and dropping ade291f (doc: link to ways to enter the ☯ symbol, 2024-05-06) that snuck in there from 070ffc5 (doc: link to ways to enter the ☯ symbol, 2024-05-06)) at some point.

@dzoep dzoep merged commit 52e6923 into drym-org:deforest-list-operations Aug 2, 2024
1 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants