aboutsummaryrefslogtreecommitdiff
path: root/monad/writer.scm
blob: 7036cb96d1aafb875975ed1a88dd7b9b247d8f41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
;;; 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 <string>) 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)))