combinators.ss
```(module combinators mzscheme

(require (lib "etc.ss")
(lib "list.ss"))

(provide curry
yrruc
constant
compose/apply
map2
map/values
fold/values
negate
conjoin
disjoin)

;; curry : (A ... B ... -> C) A ... -> B ... -> C
;; Partially applies its first argument, using the remaining arguments
;; as the function's initial parameters.
(define (curry f . args)
(lambda rest
(apply f (append args rest))))

;; yrruc : (A ... B... -> C) B ... -> A ... -> C
;; Partially applies its first argument, using the remaining arguments
;; as the function's final parameters.
(define (yrruc f . rest)
(lambda args
(apply f (append args rest))))

;; constant : V -> Any ... -> V
;; Produces a function with constant return value.
(define (constant v)
(lambda args v))

;; compose/apply :
;; (A ... -> (list B ...)) (B ... -> (list C ...)) ... ->
;; (A ... -> (list Z ...))
;; Composes functions by passing on argument lists.
(define (compose/apply first . rest)
(foldl
(lambda (f accum)
(lambda args (apply accum (apply f args))))
first
rest))

;; fold/values : (A ... B ... -> (values B ...)) (list B ...) (Listof A) ... -> (values B ...)
(define (fold/values f inits . ls)
(recur loop ([ls ls]
[results inits])
(if (ormap null? ls)
(apply values results)
(loop (map cdr ls)
(call-with-values (lambda ()
(apply f (append (map car ls) results)))
list)))))

;; map/values : n:Nat (A ... -> B ...n) (Listof A) ... -> (Listof B) ...n
;; Like map, for functions returning n values.
(define (map/values n f l-first . l-rest)
(let* ([ls (cons l-first l-rest)]
[lengths (map length ls)])
(unless (or (null? l-rest) (apply = lengths))
(raise (make-exn:fail:contract
(format
"map/values: all lists must be of same length, got lengths ~v"
lengths)
(current-continuation-marks))))
(recur loop ([ls ls])
(cond
[(ormap null? ls) (apply values (build-list n (constant null)))]
[else
(call-with-values (lambda () (apply f (map car ls)))
(call-with-values (lambda () (loop (map cdr ls)))
(lambda tails
(apply values (map cons heads tails))))))]))))

;; map2 : (A ... -> B C) (Listof A) ... -> (Listof B) (Listof C)
;; Like map, but for a function that returns 2 values.
(define (map2 f l-first . l-rest)
(apply map/values 2 f l-first l-rest))

;; negate : (A ... -> Boolean) -> A ... -> Boolean
;; Negates a predicate.
(define (negate pred)
(lambda args (not (apply pred args))))

;; conjoin : (A ... -> Boolean) ... -> A ... -> Boolean
;; Produces the conjunction of several predicates.
(define (conjoin . preds)
(lambda args (andmap (lambda (pred) (apply pred args)) preds)))

;; disjoin : (A ... -> Boolean) ... -> A ... -> Boolean
;; Produces the disjunction of several predicates.
(define (disjoin . preds)
(lambda args (ormap (lambda (pred) (apply pred args)) preds)))

)
```