;; © 2021 Idiomdrottning, BSD 1-Clause License (module brev-separate (define-ir-syntax define-syntax-rules define-ir-syntax* define-closure match-define match-define-closure call-table for-each-line with-result over c_r like? is? define-curry c 🍛 empty? eif econd define-some as-list) (import scheme (chicken base) (chicken io) (chicken syntax) fast-generic matchable miscmacros srfi-1 srfi-69) (import-for-syntax matchable miscmacros srfi-1) (define-syntax define-ir-syntax (ir-macro-transformer (lambda (e i c) `(define-syntax ,(cadr e) (ir-macro-transformer (lambda (,(i 'exp) ,(i 'inject) ,(i 'compare)) ,@(cddr e))))))) (define-syntax define-syntax-rules (syntax-rules () ((_ name arg ...) (define-syntax name (syntax-rules arg ...))))) (define-syntax define-ir-syntax* (ir-macro-transformer (lambda (e i c) `(define-syntax ,(cadr e) (ir-macro-transformer (lambda (exp ,(i 'inject) ,(i 'compare)) (match exp ,@(cddr e)))))))) (define-ir-syntax* define-closure ((define-closure bindings head body ...) (match (chicken.syntax#expand-curried-define head body '()) ((define name body) `(define ,name (let ,(let desc ((lis bindings)) (cons (list (car lis) (cadr lis)) (if (null? (cddr lis)) '() (desc (cddr lis))))) ,body)))))) (define-ir-syntax match-define `(define ,(caaadr exp) (match-lambda* ,@(map (lambda (el) (cons (cdar el) (cdr el))) (cdr exp))))) (define-for-syntax caaaddr (o caaar cddr)) (define-ir-syntax match-define-closure `(define ,(caaaddr exp) (let ,(let desc ((lis (cadr exp))) (cons (list (car lis) (cadr lis)) (if (null? (cddr lis)) '() (desc (cddr lis))))) (match-lambda* ,@(map (lambda (el) (cons (cdar el) (cdr el))) (cddr exp)))))) (match-define-closure (ht (make-hash-table)) (((call-table #!key (default #f)) key) (hash-table-ref/default ht key default)) (((call-table)) ht) (((call-table) #:update (? hash-table? new-ht)) (set! ht new-ht)) (((call-table) key val) (hash-table-set! ht key val))) (match-define-closure (ht (make-hash-table)) (((call-table* #!key (initial '()) (proc cons) (unary #f)) key) (if unary (hash-table-update! ht key proc (constantly initial)) (hash-table-ref/default ht key initial))) (((call-table*)) ht) (((call-table*) #:update (? hash-table? new-ht)) (set! ht new-ht)) (((call-table*) key val) (hash-table-update! ht key (cut proc val <>) (constantly initial)))) (define-ir-syntax* for-each-line ((for-each-line filename . body) `(for-each (lambda (,(inject 'line)) ,@body) (with-input-from-file ,filename read-lines)))) (define-ir-syntax with-result `(let* ((ret #f) (,( inject 'save) (lambda (val) (set! ret val) val))) ,@(cdr exp) ret)) (define-syntax-rule (over bindings . body) (lambda lis (apply map (lambda bindings . body) lis))) (define-ir-syntax c_r `(define (,(inject (cadr exp)) x) ,(fold list 'x (unfold-right null? (lambda (n) (case (car n) ((#\a) 'car) ((#\d) 'cdr))) cdr (cdr (butlast (string->list (symbol->string (strip-syntax (cadr exp)))))))))) ;; Pre-curried versions of popular procedures ;; only cuts out a few letters (pun intended) but still (define ((like? a) b) (equal? a b)) (define ((is? a) b) (eq? a b)) (define-syntax-rule (define-curry (name . args) . body) (define (name . friends) (if (= (length friends) (length 'args)) (apply (lambda args . body) friends) (lambda stragglers (apply name (append friends stragglers)))))) (define (🍛 name . args) (lambda stragglers (apply name (append args stragglers)))) (define c 🍛) (define-type number number?) (define-type string string?) (define-type list list?) (define-type boolean boolean?) (define-generic (empty? (boolean x)) (not x)) (define-generic (empty? (number x)) (zero? x)) (define-generic (empty? (string x)) (zero? (string-length x))) (define-generic (empty? (list x)) (null? x)) (define-ir-syntax* eif ((eif test yes no) `(let ((,(inject 'it) ,test)) (if (empty? ,(inject 'it)) ,no ,yes)))) (define-syntax econd (syntax-rules (else =>) ((econd (else result1 result2 ...)) (begin result1 result2 ...)) ((econd (test => result)) (eif test (result it))) ((econd (test => result) clause1 clause2 ...) (eif test (result it) (econd clause1 clause2 ...))) ((econd (test)) test) ((econd (test) clause1 clause2 ...) (eif test it (econd clause1 clause2 ...))) ((econd (test result1 result2 ...)) (eif test (begin result1 result2 ...))) ((econd (test result1 result2 ...) clause1 clause2 ...) (eif test (begin result1 result2 ...) (econd clause1 clause2 ...))))) (define-syntax-rule (define-some (name arg args ...) body) (define (name arg args ...) (if (empty? arg) '() body))) (define-type integer integer?) (define-type string string?) (define-type vector vector?) (define-generic (back-to (integer x)) (o string->number list->string (🍛 map integer->char))) (define-generic (back-to (string x)) list->string) (define-generic (back-to (vector x)) list->vector) (define-generic (->list (integer x)) (map char->integer (string->list (number->string x)))) (define-generic (->list (string x)) (string->list x)) (define-generic (->list (vector x)) (vector->list x)) (define ((as-list . procs) x) (eif ((apply compose procs) (->list x)) ((back-to x) it) #f)) )