(defpackage #:aoc (:use :cl) (:export :with-lines :all)) (in-package #:aoc) (defmacro with-lines ((stream var) &body body) "Loop over the lines of STREAM, executing BODY. This exposes the variable VAR and the argument-less function NEXT-LINE to the lexical environment." (let ((next-line-p (member 'next-line (alexandria:flatten body)))) `(loop :for ,var := (read-line ,stream nil) :while (not (null ,var)) :do ,(if next-line-p `(flet ((next-line () (setf ,var (read-line ,stream nil)))) ,@body) `(progn ,@body))))) (defun all (predicate list) (loop :for e :in list :with all := t :do (setf all (and all (funcall predicate e))) :finally (return all)))