(module concise mzscheme (provide (rename my-app #%app)) (require-for-syntax (lib "stx.ss" "syntax")) (require-for-template (only (lib "1.ss" "srfi") iota)) (require-for-template (only (lib "26.ss" "srfi") cut)) (require (only (lib "26.ss" "srfi") cut)) (require (only (lib "1.ss" "srfi") iota)) (define (interval n m) (if (<= n m) (interval/step n m 1) (interval/step n m -1))) (define (inclusive-interval n m) (if (<= n m) (inclusive-interval/step n m 1) (inclusive-interval/step n m -1))) (define (same-sign? x y) (positive? (* x y))) (define (interval/step n m s) (if (= n m) '() (begin (unless (same-sign? (- m n) s) (if (< n m) (error "When is less than it is required that is positive") (error "When is less than it is required that is negative"))) (if (< n m) (let loop ([c 0] [xs '()]) (let ([x (+ n (* c s))]) (if (< x m) (loop (+ c 1) (cons x xs)) (reverse! xs)))) (let loop ([c 0] [xs '()]) (let ([x (+ n (* c s))]) (if (> x m) (loop (+ c 1) (cons x xs)) (reverse! xs)))))))) (define (inclusive-interval/step n m s) (if (= n m) (list m) (begin (unless (same-sign? (- m n) s) (if (< n m) (error "When is less than it is required that is positive") (error "When is less than it is required that is negative"))) (if (< n m) (let loop ([c 0] [xs '()]) (let ([x (+ n (* c s))]) (if (<= x m) (loop (+ c 1) (cons x xs)) (reverse! xs)))) (let loop ([c 0] [xs '()]) (let ([x (+ n (* c s))]) (if (>= x m) (loop (+ c 1) (cons x xs)) (reverse! xs)))))))) (define-syntax (my-app stx) (define (bracket-shaped? stx) (equal? (syntax-property stx 'paren-shape) #\[)) (define (set-shaped? stx) (equal? (syntax-property stx 'paren-shape) #\{)) (define (dots? stx) (and (identifier? stx) (module-or-top-identifier=? stx (datum->syntax-object stx '...)))) (define (range? stx) (syntax-case* stx (..) module-or-top-identifier=? [[_ a .. b] (bracket-shaped? stx) ] [[_ a .. b s] (bracket-shaped? stx)] [[_ a dots b] (and (bracket-shaped? stx) (dots? #'dots)) #t] [[_ a dots b s] (and (bracket-shaped? stx) (dots? #'dots)) #t] [[_ a .. b s] (bracket-shaped? stx)] [[_ count] (bracket-shaped? stx)] [[_ count start] (bracket-shaped? stx)] [[_ count start step] (bracket-shaped? stx)] [_ #f])) (define (handle-range stx) (syntax-case* stx (..) module-or-top-identifier=? [[_ from .. to] (syntax/loc stx (interval from to))] [[_ from .. to step] (syntax/loc stx (interval/step from to step))] [[_ from dots to] (dots? #'dots) (syntax/loc stx (inclusive-interval from to))] [[_ from dots to step] (dots? #'dots) (syntax/loc stx (inclusive-interval/step from to step))] [[_ count] (syntax/loc stx (iota count))] [[_ count start] (syntax/loc stx (iota count start))] [[_ count start step] (syntax/loc stx (iota count start step))] [_else (error stx)])) (define (handle-cut stx) (define (underscore-to-slot stx) (syntax-case* stx (_) module-or-top-identifier=? [_ (syntax/loc stx <>)] [_else stx])) (with-syntax ([(se ...) (map underscore-to-slot (cdr (syntax->list stx)))]) (syntax/loc stx (cut se ...)))) (syntax-case* stx (.. : is ->) module-or-top-identifier=? ; lambda shorthand [{_ n ... -> expr} (set-shaped? stx) (syntax/loc stx (lambda (n ...) expr))] [{expr-or-slot ...} (set-shaped? stx) (handle-cut stx)] ; "comprehension" syntax [[_ expr : n is while-pred-expr] (bracket-shaped? stx) (syntax/loc stx (let loop ([n 0]) (if while-pred-expr (cons expr (loop (+ n 1))) '())))] [(_ expr : n is while-pred-expr filter-expr) (bracket-shaped? stx) (syntax/loc stx (let loop ([n 0]) (if while-pred-expr (if filter-expr (cons expr (loop (+ n 1))) (loop (+ n 1))) '())))] [(_ n : while-pred-expr) (bracket-shaped? stx) (syntax/loc stx (let loop ([n 0]) (if while-pred-expr (cons n (loop (+ n 1))) '())))] [(_ n : while-pred-expr filter-expr) (bracket-shaped? stx) (syntax/loc stx (let loop ([n 0]) (if while-pred-expr (if filter-expr (cons n (loop (+ n 1))) (loop (+ n 1))) '())))] ; ranges [range (range? stx) (handle-range stx)] [(_ . more) (syntax/loc stx (#%app . more))]))) (require concise) ;;; ;;; RANGES ;;; 'normal-range (equal? [1 .. 4] '(1 2 3)) (equal? [1 ... 4] '(1 2 3 4)) 'reverse-range (equal? [4 .. 1] '(4 3 2)) (equal? [4 ... 1] '(4 3 2 1)) 'empty-or-one-element-range (equal? [4 .. 4] '()) (equal? [4 ... 4] '(4)) 'normal-range-with-step (equal? [1 .. 7 2] '(1 3 5)) (equal? [1 .. 8 2] '(1 3 5 7)) (equal? [1 ... 7 2] '(1 3 5 7)) (equal? [1 ... 8 2] '(1 3 5 7)) 'reverse-range (equal? [4 .. 1] '(4 3 2)) (equal? [4 ... 1] '(4 3 2 1)) 'reverse-range-with-step (equal? [7 .. 1 -2] '(7 5 3)) ; TODO: better error location for 2 instead of -2 (equal? [8 .. 1 -2] '(8 6 4 2)) (equal? [7 ... 1 -2] '(7 5 3 1)) (equal? [8 ... 1 -2] '(8 6 4 2)) ;;; ;;; IOTA ;;; (equal? [4] '(0 1 2 3)) (equal? [4 3] '(3 4 5 6)) (equal? [4 3 5] '(3 8 13 18)) ;;; ;;; "COMPREHENSION" ;;; (equal? [n : (< n 5)] '(0 1 2 3 4)) (equal? [n : (< n 5) (even? n)] '(0 2 4)) (equal? [(* n n) : n is (< n 5)] '(0 1 4 9 16)) (equal? [(* n n) : n is (< n 5) (even? n)] '(0 4 16)) ;;; ;;; "CURRY" ;;; (equal? ({- _} 3) -3) (equal? ({list 1 _ 3 _ 5 } 2 4) '(1 2 3 4 5)) ;;; ;;; LAMBDA ;;; (equal? (map {n -> (+ n 1)} [0 ... 3]) '(1 2 3 4)) ;;; ;;; EXAMPLES ;;; (define (square? n) (= (integer-sqrt n) (sqrt n))) (equal? (map {+ _ 3} [1 ... 3]) '(4 5 6)) (equal? (filter {square? _} [1 ... 100]) '(1 4 9 16 25 36 49 64 81 100)) (equal? (filter {n -> (and (odd? n) (square? n))} [1 ... 100]) '(1 9 25 49 81))