;;; Commentary: ;; The writer monad creates a context where strings are automatically collected. ;; This is useful both for logging and output construction. ;; ;; The writer monad uses the state monad internally, but it's considered a leak ;; in the abstraction to access it directly (even though there is nothing ;; stoping you). ;;; Code: (define-module (monad writer) #:use-module (monad) #:use-module (monad state) #:use-module (oop goops) #:re-export (>>) #:export (w return-writer run-writer with-writer)) (define (w str) "writes str to the current writer monad" (modify (lambda (st) (string-append st str)))) (define return-writer return-state) (define (run-writer w) "Wrapper around run-state, but inserts an empty string as starting state." (run-state w "")) (define-method (>> (s ) other) "A bit of a hack, but this allows strings to be placed directly inside a @code{do} block, and have them written to the current writer context." (>> (w s) other)) (define (with-writer proc . values) "Runs a regular procedure on values, but also logs the call" (do let return = (apply proc values) (format #f "Applied ~s to ~s ⇒ ~s\n" (procedure-name proc) values return) (return-writer return)))