diff options
| -rw-r--r-- | ravanan/utils.scm | 71 |
1 files changed, 69 insertions, 2 deletions
diff --git a/ravanan/utils.scm b/ravanan/utils.scm index fbf71ed..9cc120a 100644 --- a/ravanan/utils.scm +++ b/ravanan/utils.scm @@ -1,5 +1,5 @@ ;;; ravanan --- High-reproducibility CWL runner powered by Guix -;;; Copyright © 2024, 2025 Arun Isaac <arunisaac@systemreboot.net> +;;; Copyright © 2024–2026 Arun Isaac <arunisaac@systemreboot.net> ;;; ;;; This file is part of ravanan. ;;; @@ -22,7 +22,11 @@ #:use-module (ice-9 filesystem) #:use-module (ice-9 match) #:export (string-trim-prefix - load-script) + load-script + mapn + map2 + foldn + findn) #:declarative? #f) (define (string-trim-prefix prefix str) @@ -56,3 +60,66 @@ before loading script." ;; probably safe to ignore this warning since we use load only within a ;; dummy module. (load script-file))))) + +(define (mapn proc lst n) + "Map the procedure @var{proc} over list @var{lst} and return a list containing +the results. @var{proc} must return @var{n} values, in which case, @var{n} lists +are returned. For example, + +(mapn (lambda (n) + (values (expt n 2) + (expt n 3))) + (iota 5)) +=> (0 1 4 9 16) +=> (0 1 8 27 64)" + (apply values + (match lst + ;; With an empty list, we cannot know the number of values + ;; proc would return. Hence this special case. + (() (make-list n '())) + (_ + (apply zip + (map (lambda (x) + (call-with-values (cut proc x) list)) + lst)))))) + +(define map2 + (cut mapn <> <> 2)) + +(define (foldn proc lst . inits) + "Apply @var{proc} to the elements of @var{lst} to build a result, and return +that result. @var{proc} may return multiple values, in which case, an equal +number of values are returned. Each @var{proc} call is @code{(proc element +previous ...)} where @code{element} is an element of @var{lst}, and +@code{(previous ...)} is the return from the previous call to @var{proc} or the +given @var{inits} for the first call. For example, + +(foldn (lambda (n sum sum-of-squares) + (values (+ sum n) + (+ sum-of-squares (expt n 2)))) + (iota 10) + 0 0) +=> 45 +=> 285" + (apply values + (fold (lambda (element results) + (call-with-values (cut apply proc element results) list)) + inits + lst))) + +(define (findn pred . lists) + "Return the first elements of @var{lists} that satisfies the predicate @var{pred} +and a list of @code{#f} if no such elements are found. @var{pred} must accept as +many arguments as there are @var{lists}. + +(findn (lambda (x y) + (and (odd? x) + (odd? y))) + (list 2 3 3) + (list 3 5 8)) +=> 3 +=> 5" + (apply values + (or (find (cut apply pred <...>) + (apply zip lists)) + (make-list (length lists) #f)))) |
