From 25e08d89e3553b46e247fd91dfaa2bd6eb11ac79 Mon Sep 17 00:00:00 2001 From: Colin Okay Date: Fri, 9 Sep 2022 09:42:05 -0500 Subject: Refactor: collector functions are now defined with defun/t --- gtwiwtg.lisp | 61 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 11 deletions(-) (limited to 'gtwiwtg.lisp') diff --git a/gtwiwtg.lisp b/gtwiwtg.lisp index 49b7d1b..67ee209 100644 --- a/gtwiwtg.lisp +++ b/gtwiwtg.lisp @@ -188,6 +188,8 @@ E.g. If TO is NIL, then the generator produces an infinite series of values. " + :tests + :end (let ((comparator (if (plusp by) (if inclusive #'<= #'<) (if inclusive #'>= #'>)))) @@ -761,23 +763,34 @@ Example: building data (setf ,acc ,expr)) ,acc)) - -(defun collect (gen) +(defun/t collect (gen) "Consumes GEN by collecting its values into a list." + :tests + (:program test-collect) + :end (nreverse (fold (xs nil) (x gen) (cons x xs)))) -(defun take (n gen) +(defun/t take (n gen) "Consumes GEN by collecting its first N values into a list" + :tests + (:program test-take) + :end (nreverse (fold (xs nil) (x (zip! gen (times n))) (cons (car x) xs)))) -(defun pick-out (indexes gen) +(defun/t pick-out (indexes gen) "Consumes GEN by picking out certain members by their index. INDEXES is a list of non-negative integers. Returns a list of values from GEN such that each value was an element of indexes." + :tests + (:program test-pick-out) + (:fails (() (range))) ; index list cannot be null + (:fails ('(-10) (range))) ; indices cannot be negative + :end + (assert (notany #'minusp indexes)) (let ((acc (make-array (length indexes)))) (for (x idx) (zip! gen (times (1+ (apply #'max indexes)))) (when (member idx indexes) @@ -788,22 +801,42 @@ of indexes." :do (setf (aref acc i) x)))) (concatenate 'list acc))) -(defun size (gen) +(defun/t size (gen) "Consumes GEN by calculating its size." - (fold (n 0) (x gen) (1+ n))) + :tests + (= ((seq nil)) 0) + (= ((range :to 3)) 3) + :end + (fold (n 0) (x (map! (constantly 1) gen)) (+ n x))) -(defun maximum (gen) +(defun/t maximum (gen) "Consumes GEN, returning its maximum value." + :tests + (= ((range :to 5)) 4) + (= ((range :to 5 :inclusive t)) 5) + (= ((range :from -10 :to 0 :by 3)) -1) + (:fails ((seq "hey"))) + :end (fold (m nil) (x gen) (if m (max m x) x))) -(defun minimum (gen) +(defun/t minimum (gen) "Consumes GEN, returning its minimum value." + :tests + (= ((range :to 5)) 0) + (= ((range :from -10 :to 0 :by 3)) -10) + (:fails ((seq "hey"))) + :end (fold (m nil) (x gen) (if m (min m x) x))) -(defun average (gen) +(defun/t average (gen) "Consumes GEN, returning its average value." + :tests + (= ((range :from 1 :to 4 :inclusive t)) 5/2) + (:signals ((seq nil)) division-by-zero) ; empty sum signals division by zero + (:fails ((seq "foo"))) ; numeric sequences only + :end (let ((sum 0) (count 0)) (for x gen @@ -811,9 +844,12 @@ of indexes." (incf count)) (/ sum count))) -(defun argmax (fn gen) +(defun/t argmax (fn gen) "Consumes GEN. Returns a pair (X . VALUE) such that (FUNCALL FN X) is maximal among the values of GEN. VALUE is the value of (FUNCALL FN X)" + :tests + (:program test-argmax) + :end (fold (am nil) (arg gen) (let ((val (funcall fn arg))) @@ -821,9 +857,12 @@ is maximal among the values of GEN. VALUE is the value of (FUNCALL FN X)" (cons arg val) am)))) -(defun argmin (fn gen) +(defun/t argmin (fn gen) "Consumes GEN. Returns a pair (X . VALUE) such that (FUNCALL FN X) is minimal among the values of GEN. VALUE is the value of (FUNCALL FN X)" + :tests + (:program test-argmin) + :end (fold (am nil) (arg gen) (let ((val (funcall fn arg))) -- cgit v1.2.3