lib/srfi/210.scm

Summary

Maintainability
Test Coverage
;; Copyright © Marc Nieper-Wißkirchen (2020).

;; Permission is hereby granted, free of charge, to any person
;; obtaining a copy of this software and associated documentation files
;; (the "Software"), to deal in the Software without restriction,
;; including without limitation the rights to use, copy, modify, merge,
;; publish, distribute, sublicense, and/or sell copies of the Software,
;; and to permit persons to whom the Software is furnished to do so,
;; subject to the following conditions:

;; The above copyright notice and this permission notice (including the
;; next paragraph) shall be included in all copies or substantial
;; portions of the Software.

;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
;; BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
;; ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
;; CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;; SOFTWARE.

;;;;;;;;;;;;
;; Syntax ;;
;;;;;;;;;;;;

(define-syntax apply/mv
  (syntax-rules ()
    ((apply/mv operator operand1 ... producer)
     (letrec-syntax
         ((aux (syntax-rules ::: ()
                 ((aux %operator () ((%operand1 arg1) :::) %producer)
                  (let-values (((proc) %operator)
                               ((arg1) %operand1) :::
                               (args %producer))
                    (apply proc arg1 ::: args)))
                 ((aux %operator (%operand1 operand2 :::) (temp :::) %producer)
                  (aux %operator (operand2 :::) (temp ::: (%operand1 arg1))
                       %producer)))))
       (aux operator (operand1 ...) () producer)))))

(define-syntax call/mv
  (syntax-rules ()
    ((call/mv consumer producer1 ...)
     (letrec-syntax
         ((aux (syntax-rules ::: ()
                 ((aux %consumer () ((%producer1 args1) :::))
                  (let-values (((proc) %consumer)
                               (args1 %producer1) :::)
                    (apply proc (append args1 :::))))
                 ((aux %consumer (%producer1 producer2 :::) (temp :::))
                  (aux %consumer (producer2 :::) (temp ::: (%producer1 args1)))))))
       (aux consumer (producer1 ...) ())))))

(define-syntax list/mv
  (syntax-rules ()
    ((list/mv element1 ... producer)
     (apply/mv list element1 ... producer))))

(define-syntax vector/mv
  (syntax-rules ()
    ((vector/mv element1 ... producer)
     (apply/mv vector element1 ... producer))))

(define-syntax box/mv
  (syntax-rules ()
    ((box/mv element1 ... producer)
     (apply/mv box element1 ... producer))))

(define-syntax value/mv
  (syntax-rules ()
    ((value/mv index operand1 ... producer)
     (apply/mv value index operand1 ... producer))))

(define-syntax coarity
  (syntax-rules ()
    ((coarity producer)
     (let-values ((res producer))
       (length res)))))

(define-syntax set!-values
  (syntax-rules ()
    ((set!-values (var1 ...) producer)
     (letrec-syntax
         ((aux (syntax-rules ::: ()
                 ((aux () ((%var1 temp1) :::) %producer)
                  (let-values (((temp1 ::: . temp*) %producer))
                    (set! %var1 temp1) :::))
                 ((aux (%var1 var2 :::) (temp :::) %producer)
                  (aux (var2 :::) (temp ::: (%var1 temp1)) %producer)))))
       (aux (var1 ... ) () producer)))
    ((set!-values (var1 ... . var*) producer)
     (letrec-syntax
         ((aux (syntax-rules ::: ()
                 ((aux () ((%var1 temp1) ::: (%var* temp*)) %producer)
                  (let-values (((temp1 ::: . temp*) %producer))
                    (set! %var1 temp1) :::
                    (set! %var* temp*)))
                 ((aux (%var1 var2 :::) (temp :::) %producer)
                  (aux (var2 :::) (temp ::: (%var1 temp1)) %producer)))))
       (aux (var1 ... var*) () producer)))
    ((set!-values var* producer)
     (let-values ((temp*) producer)
       (set! var* temp*)))))

(define-syntax with-values
  (syntax-rules ()
    ((with-values producer consumer)
     (apply/mv consumer producer))))

(define-syntax case-receive
  (syntax-rules ()
    ((case-receive producer clause ...)
     (with-values producer
       (case-lambda clause ...)))))

(define-syntax bind/mv
  (syntax-rules ()
    ((bind/mv producer transducer ...)
     (bind/list (list/mv producer) transducer ...))))

;;;;;;;;;;;;;;;;
;; Procedures ;;
;;;;;;;;;;;;;;;;

(define (list-values lis)
  (apply values lis))

(define (vector-values vec)
  (list-values (vector->list vec)))

;;(define box-values unbox)

(define (value k . objs)
  (list-ref objs k))

(define identity values)

(define compose-left
  (case-lambda
    (() identity)
    ((transducer . transducers)
     (let f ((transducer transducer) (transducers transducers))
       (if (null? transducers)
           transducer
           (let ((composition (f (car transducers) (cdr transducers))))
             (lambda args
               (apply/mv composition (apply transducer args)))))))))

(define compose-right
  (case-lambda
    (() identity)
    ((transducer . transducers)
     (let f ((transducer transducer) (transducers transducers))
       (if (null? transducers)
           transducer
           (let ((composition (f (car transducers) (cdr transducers))))
             (lambda args
               (apply/mv transducer (apply composition args)))))))))

(define (map-values proc)
  (lambda args
    (list-values (map proc args))))

(define bind/list
  (case-lambda
    ((lis) (list-values lis))
    ((lis transducer) (apply transducer lis))
    ((lis transducer . transducers)
     (apply bind/list (list/mv (apply transducer lis)) transducers))))

(define (bind/box bx . transducers)
  (apply bind/list (list/mv (unbox bx)) transducers))

(define (bind obj . transducers)
  (apply bind/list (list obj) transducers))