Fixed named update and a bug in accumulating
* goof.scm: Removed positional updates and fixed named updates * iterators.scm: Fixed bug in accumulating where only lists were supported.
This commit is contained in:
		
							parent
							
								
									b3efccb4aa
								
							
						
					
					
						commit
						f2496604d5
					
				
					 3 changed files with 55 additions and 61 deletions
				
			
		
							
								
								
									
										18
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
										
									
									
									
								
							|  | @ -1,14 +1,14 @@ | ||||||
| # goof-loop - a scheme looping facility | # goof-loop - a scheme looping facility | ||||||
| 
 | 
 | ||||||
| WARNING: CURRENTLY PRE-ALPHA. The examples in this document are not consistent with the current direction I am pushing this (even though they _should_ work.  | WARNING: CURRENTLY PRE-ALPHA. The examples in this document are not consistent with the current direction I am pushing this (even though they _should_ work). | ||||||
| 
 | 
 | ||||||
| goof-loops aims to be an amalgamation of the racket for loops and Alex Shinn's foof-loop. We are many that found racket's for loops a breeze of fresh air, but in the end their most general forms (for/fold and for/foldr) are kinda odd to work with. If you choose not to use those general for loops, you cannot express arbitrary transformations, like say a fibonacci sequence, since for clauses cannot reference eachother. This is understandable given how they are tied to the underlying racket sequences, but still somewhat disappointing. goof-loop tries to fix this: | goof-loops aims to be an amalgamation of the racket for loops and Alex Shinn's (chibi-loop). We are many that found racket's for loops a breeze of fresh air, but in the end their most general forms (for/fold and for/foldr) are kinda odd to work with. If you choose not to use those general for loops, you cannot express arbitrary transformations, like say a fibonacci sequence, since for clauses cannot reference eachother. goof-loop tries to fix this: | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| (loop ((:for a (in 0 b)) | (loop ((:for a (in 0 b)) | ||||||
|        (:for b (in 1 (+ a b))) |        (:for b (in 1 (+ a b))) | ||||||
|        (:for count (up-from 0 (to 1000))) |        (:for count (up-from 0 (to 1000))) | ||||||
|        (:for acc (listing b))) |        (:acc acc (listing b))) | ||||||
|   => acc |   => acc | ||||||
|   (display b) (newline)) |   (display b) (newline)) | ||||||
| ``` | ``` | ||||||
|  | @ -22,7 +22,7 @@ Compared to foof-loop, some things are added. Apart from minor syntactic changes | ||||||
| (loop ((:for a (in-list lst)) | (loop ((:for a (in-list lst)) | ||||||
|        (:when (pair? a)) |        (:when (pair? a)) | ||||||
|        (:for b (in-list a)) |        (:for b (in-list a)) | ||||||
|        (:for acc (summing b))) |        (:acc acc (summing b))) | ||||||
|   => acc) |   => acc) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | @ -54,7 +54,7 @@ only :acc clauses are visible in the final-expression. This is due to for-clause | ||||||
| 
 | 
 | ||||||
| (with var 10 (- var 1) negative?) => (:for var (in 10 (- var 10) (negative? var))) | (with var 10 (- var 1) negative?) => (:for var (in 10 (- var 10) (negative? var))) | ||||||
| 
 | 
 | ||||||
| I plan to remove non-named variable updates. That is a minor inconveniance, but unnamed updates has been my largest source of bugs, so I have grown to hate them. | Positional updates of variables is not supported, due to goof-loop reordering the loop-vars - which there are reasons for. | ||||||
| 
 | 
 | ||||||
| ### similarities | ### similarities | ||||||
| 
 | 
 | ||||||
|  | @ -70,10 +70,11 @@ You can of course still have a larger control of your loops: | ||||||
| ;; => (-1 4 -9 16 -25 36 -49 64 -81 100) | ;; => (-1 4 -9 16 -25 36 -49 64 -81 100) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Named updates have a bug, sadly, but works if there is only _one_ instance of the iteration macro. This doesn't curretnly work, but will in a little time: | Named updates also work. | ||||||
| 
 | 
 | ||||||
| ``` | ``` | ||||||
| ;; Shamelessly stolen from Taylor Campbell's foof-loop documentation | ;; Shamelessly stolen from Taylor Campbell's foof-loop documentation | ||||||
|  | (define (partition list predicate) | ||||||
|   (loop continue ((:for element (in-list list)) |   (loop continue ((:for element (in-list list)) | ||||||
|                   (:acc satisfied (in  '())) |                   (:acc satisfied (in  '())) | ||||||
|                   (:acc  unsatisfied  (in '()))) |                   (:acc  unsatisfied  (in '()))) | ||||||
|  | @ -82,6 +83,9 @@ Named updates have a bug, sadly, but works if there is only _one_ instance of th | ||||||
|      (if (predicate element) |      (if (predicate element) | ||||||
|          (continue (=> satisfied (cons element satisfied))) |          (continue (=> satisfied (cons element satisfied))) | ||||||
|          (continue (=> unsatisfied (cons element unsatisfied)))))) |          (continue (=> unsatisfied (cons element unsatisfied)))))) | ||||||
|  | 
 | ||||||
|  | (partition '(1 2 3 4 5) odd?) | ||||||
|  | ;; => (values (1 3 5) (2 4)) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -97,6 +101,8 @@ Is (:for var (in init step stop)) and (:acc var (in init update)) good syntax? t | ||||||
| 
 | 
 | ||||||
| Add racket #:final clauses. | Add racket #:final clauses. | ||||||
| 
 | 
 | ||||||
|  | Add simple versions of loop. loop/list, loop/sum, loop/last, loop/first, and so on. | ||||||
|  | 
 | ||||||
| ## foof, what a guy | ## foof, what a guy | ||||||
| 
 | 
 | ||||||
| I have previously expressed some admiration for Alex and I will do it again. The source of chibi loop is extremely elegant, and all but the hairiest part is written in syntax-rules. Not only has he written my two favourite SRFIs, his input in all the other discussions I have seen is always on-point, pragmatic and generally fantastic. He neither knows of this project, nor embraces it in any way. Y'all should go look at the source of (chibi loop) though. | I have previously expressed some admiration for Alex and I will do it again. The source of chibi loop is extremely elegant, and all but the hairiest part is written in syntax-rules. Not only has he written my two favourite SRFIs, his input in all the other discussions I have seen is always on-point, pragmatic and generally fantastic. He neither knows of this project, nor embraces it in any way. Y'all should go look at the source of (chibi loop) though. | ||||||
|  |  | ||||||
							
								
								
									
										50
									
								
								goof.scm
									
										
									
									
									
								
							
							
						
						
									
										50
									
								
								goof.scm
									
										
									
									
									
								
							|  | @ -37,12 +37,16 @@ | ||||||
| ;;   * Adds :when, :unless, and :break clauses that controls when the loop | ;;   * Adds :when, :unless, and :break clauses that controls when the loop | ||||||
| ;;     body executes and when values are collected by accumulating for clauses. | ;;     body executes and when values are collected by accumulating for clauses. | ||||||
| ;;     similar to how #:when, #:unless and #:break works in racket. | ;;     similar to how #:when, #:unless and #:break works in racket. | ||||||
| ;;   * Planned: add support for subloops, akin to what the starified loops of |  | ||||||
| ;;     racket do. |  | ||||||
| ;; | ;; | ||||||
| ;;   It restricts chibi loops in the following ways: | ;;   It restricts chibi loops in the following ways: | ||||||
| ;;    * with- and for-clauses  are no longer visible in the final expression, for that you | ;;    * with- and for-clauses  are no longer visible in the final expression, for that you | ||||||
| ;;      must use a clause for which I don't have a name yet. | ;;      must use an accumulator clause. | ||||||
|  | ;;    * Positional update is not supported. It seems error-prone once you start | ||||||
|  | ;;      having a lot of loop variables, and because goof-loop does some re-ordering | ||||||
|  | ;;      that foof loop does not. For example: | ||||||
|  | ;;        (:for a (in 0 (+ a 1))) (:acc acc (in '() (cons a acc))) | ||||||
|  | ;;      are actually reordered in a loop, because accumulators and for loops are separated | ||||||
|  | ;;      due to having to propagate the accumulators through the loop. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| (use-modules (helpers) | (use-modules (helpers) | ||||||
|  | @ -51,7 +55,8 @@ | ||||||
| (include "iterators.scm") | (include "iterators.scm") | ||||||
| 
 | 
 | ||||||
| ;; TODO: Add intermediate subloops. Make sure that accumulators are properly propagated. | ;; TODO: Add intermediate subloops. Make sure that accumulators are properly propagated. | ||||||
| ;; TODO. fix let-kw-form. Don't use mutation. This should work:(define (partition predicate list) | ;; DONE: fix let-kw-form. Don't use mutation. This should be tested: | ||||||
|  | ;; (define (partition predicate list) | ||||||
| ;;   (loop continue ((:for element (in-list list)) | ;;   (loop continue ((:for element (in-list list)) | ||||||
| ;;                   (:acc satisfied (in  '())) | ;;                   (:acc satisfied (in  '())) | ||||||
| ;;                   (:acc  unsatisfied  (in '()))) | ;;                   (:acc  unsatisfied  (in '()))) | ||||||
|  | @ -131,6 +136,9 @@ | ||||||
|      (cl-next () ((var init update)) () () () ((var var)) orig name l a v c r f ul uw ub (clauses ...) . body)) |      (cl-next () ((var init update)) () () () ((var var)) orig name l a v c r f ul uw ub (clauses ...) . body)) | ||||||
|     ((_ orig name l a v c r f ul uw ub ((:acc var (in init)) clauses ...) . body) |     ((_ orig name l a v c r f ul uw ub ((:acc var (in init)) clauses ...) . body) | ||||||
|      (cl-next () ((var init var)) () () () ((var var)) orig name l a v c r f ul uw ub (clauses ...) . body)) |      (cl-next () ((var init var)) () () () ((var var)) orig name l a v c r f ul uw ub (clauses ...) . body)) | ||||||
|  |     ;; Accumulator clause with a proper accumulator. | ||||||
|  |     ((_ orig name l a v c r f ul uw ub ((:acc id ids ... (iterator source ...)) clauses ...) . body) | ||||||
|  |      (iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub (clauses ...) . body)) | ||||||
| 
 | 
 | ||||||
|     ;; user-whens |     ;; user-whens | ||||||
|     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub ((:when test) clauses ...) . body) |     ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub ((:when test) clauses ...) . body) | ||||||
|  | @ -366,26 +374,13 @@ | ||||||
| (define (syntax= s1 s2) | (define (syntax= s1 s2) | ||||||
|   (equal? (syntax->datum s1) (syntax->datum s2))) |   (equal? (syntax->datum s1) (syntax->datum s2))) | ||||||
| 
 | 
 | ||||||
| (define (named-update? syn) | (define (update-name params name val) | ||||||
|   (syntax-case syn (=>) |  | ||||||
|     ((=> var update) #t) |  | ||||||
|     (_ #f))) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| (define (update-psn! params psn val) |  | ||||||
|   (list-set! params psn |  | ||||||
|              (list (car (list-ref params psn)) val))) |  | ||||||
| 
 |  | ||||||
| (define (update-name! params name val) |  | ||||||
|   (let loop ((params params)) |  | ||||||
|   (cond |   (cond | ||||||
|    ((null? params) (error "unknown loop parameter name " name (list '=> name val))) |    ((null? params) (error "unknown loop parameter name " name (list '=> name val))) | ||||||
|    ((syntax= name (caar params)) |    ((syntax= name (caar params)) | ||||||
|       (set-cdr! (car params) (list val)) |     (cons (list (caar params) val) (cdr params))) | ||||||
|       (display (syntax->datum val)) |  | ||||||
|       ) |  | ||||||
|    (else |    (else | ||||||
|       (loop (cdr params)))))) |     (cons (car params) (update-name (cdr params) name val))))) | ||||||
| 
 | 
 | ||||||
| (define (syntax->list stx) | (define (syntax->list stx) | ||||||
|   (syntax-case stx () |   (syntax-case stx () | ||||||
|  | @ -396,23 +391,16 @@ | ||||||
|     ((_ macro-name (loop-name (var step) ...) . body) |     ((_ macro-name (loop-name (var step) ...) . body) | ||||||
|      (let-syntax ((macro-name |      (let-syntax ((macro-name | ||||||
|                    (lambda (stx) |                    (lambda (stx) | ||||||
|                      ;; this way of formulating params means it is an alist with syntax objects |  | ||||||
|                      ;; as keys instead of a list of syntax objects |  | ||||||
|                      (define params (list #'(var step) ...)) |  | ||||||
|                      (with-ellipsis ::: |                      (with-ellipsis ::: | ||||||
|                        (let loop ((lst (cdr (syntax->list stx))) (pos 0)) |                        (let loop ((lst (cdr (syntax->list stx))) | ||||||
|  |                                   (params (list #'(var step) ...))) | ||||||
|                          (if (null? lst) |                          (if (null? lst) | ||||||
|                              (with-syntax ((((v s) :::) params)) |                              (with-syntax ((((v s) :::) params)) | ||||||
|                                #'(loop-name s :::)) |                                #'(loop-name s :::)) | ||||||
|                              (syntax-case (car lst) (=>) |                              (syntax-case (car lst) (=>) | ||||||
|                                ((=> name val) |                                ((=> name val) | ||||||
|                                 (update-name! params #'name #'val) |                                 (loop (cdr lst) (update-name params #'name #'val))) | ||||||
|                                 (loop (cdr lst) #f)) |                                (_ (error "Malformed looping clause in macro"))))))))) | ||||||
|                                (val pos |  | ||||||
|                                  (begin |  | ||||||
|                                    (update-psn! params psn #'val) |  | ||||||
|                                    (loop (cdr lst) (+ pos 1)))) |  | ||||||
|                                (_ (error "Positional arguments cannot be updated after a named argument"))))))))) |  | ||||||
|        . body)))) |        . body)))) | ||||||
|                         |                         | ||||||
|                         |                         | ||||||
|  |  | ||||||
|  | @ -268,7 +268,7 @@ | ||||||
|      (accumulating (kons final i) ((var cursor) x) n . rest)) |      (accumulating (kons final i) ((var cursor) x) n . rest)) | ||||||
|     ((accumulating (kons final init) ((var cursor) (expr (if check))) n . rest) |     ((accumulating (kons final init) ((var cursor) (expr (if check))) n . rest) | ||||||
|      (n ((tmp-kons kons)) |      (n ((tmp-kons kons)) | ||||||
|         ((cursor '() (if check (tmp-kons expr cursor) cursor))) |         ((cursor init (if check (tmp-kons expr cursor) cursor))) | ||||||
|         () |         () | ||||||
|         () |         () | ||||||
|         () |         () | ||||||
|  | @ -276,7 +276,7 @@ | ||||||
|         . rest)) |         . rest)) | ||||||
|     ((accumulating (kons final init) ((var cursor) (expr)) n . rest) |     ((accumulating (kons final init) ((var cursor) (expr)) n . rest) | ||||||
|      (n ((tmp-kons kons)) |      (n ((tmp-kons kons)) | ||||||
|         ((cursor '() (tmp-kons expr cursor))) |         ((cursor init (tmp-kons expr cursor))) | ||||||
|         () |         () | ||||||
|         () |         () | ||||||
|         () |         () | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus
						Linus