(read-enable 'curly-infix) (use-modules (oop goops) (oop goops describe) (ice-9 match) (srfi srfi-1)) (define-class ()) (define-generic null) (define-generic mappend) (define (<> . args) (fold mappend (null (car args)) (reverse args))) (define-method (mappend (a ) (b )) (append a b)) (define-method (mappend (a ) (b )) a) (define-method (mappend (a ) (b )) b) (define-method (mappend (a ) (b )) '()) (define-method (null (a )) '()) (define-method (null (a )) '()) (define-macro (null type) (symbol-append type '-null)) (define-class ()) (define-generic map) (define-class ( )) (define-generic bind) #; (define-generic return) (define-class () (slot #:init-value #f #:init-keyword #:slot) (just #:init-value #t #:init-keyword #:just)) (define (nothing) (make #:just #f)) (define (just obj) (make #:just #t #:slot obj)) (define (nothing? this) (not (slot-ref this 'just))) (define (just? this) (not (nothing? this))) (define-method (write (this ) port) (if (just? this) (format port "[Just ~s]" (slot-ref this 'slot)) (format port "[Nothing]"))) (define-class () (slot #:init-keyword #:slot) (dir #:init-keyword #:dir #:init-value 'left)) (define (left val) "Error values" (make #:slot val #:dir 'left)) (define (right val) "Good values" (make #:slot val #:dir 'right)) (define-method (write (this ) port) (format port "[~a ~s]" (slot-ref this 'dir) (slot-ref this 'slot))) (define-method (>>= (this ) (proc )) (case (slot-ref this 'dir) ((left) this) ((right) (match this (($ slot) (proc slot)))))) (define return-either right) (define return-optional just) ;; bind :: Monad m => m a -> (a -> m b) -> m b ;; return :: Monad m => a -> m a ;; map :: Functor f => (a -> b) -> f a -> f b (define-method (>>= (this ) (proc )) (cond ((nothing? this) (nothing)) ((just? this) (match this (($ slot) (proc slot)))))) (define-method (>>= (this ) proc) '()) (define-method (>>= (this ) (proc )) (concatenate! (map proc this))) (define-class () (value #:init-keyword #:value) (monoid #:init-keyword #:monoid)) (define (writer value context) (make #:value value #:monoid context)) (define-method (>>= (this ) (proc )) (match this (($ value monoid) (match (proc value) (($ nval ncontext) (writer nval { monoid <> ", " <> ncontext })))))) (define-method (write (this ) port) (match this (($ value monoid) (format port "[Writer ~s, ~s]" value monoid)))) (define-syntax do (syntax-rules (<- let =) ((_ let var = val rest ...) (let ((var val)) (do rest ...))) ((_ ptrn <- val rest ...) (<- ptrn val rest ...)) ((_ a) a) ((_ token rest ...) (begin token (do rest ...))))) (define-syntax <- (lambda (x) (syntax-case x (just left right writer) ((_ (just var) val rest ...) #'(>>= val (lambda (var) rest ...))) ((_ (writer var) val rest ...) #'(>>= val (lambda (var) rest ...))) #; ((_ (left var) val rest ...) ; #'(>>= val (lambda (var) rest ...))) #; ((_ (right var) val rest ...) ; #'(>>= val (lambda (var) rest ...)))))) ;;; Examples: ;;; These are do in the conext of the optional monad. (do (just x) <- (just 10) x) ; => 10 (do let y = (just 10) (just x) <- y (+ x 5)) ; => 15 (do (just x) <- (nothing) (+ x 5)) ; => [Nothing] ;;; (do let either = left 10 (left x) <- either x) ; EVALUATION ERROR ;; Int -> Writer Int String (define (log-number n) (writer n (format #f "Got nuber: ~a" n))) (define (mult-with-log) (do (writer a) <- (log-number 3) (writer b) <- (log-number 5) (* a b))) (do (writer a) <- (log-number 1) a) ; EVALUATION ERROR (begin { (log-number 1) >>= log-number }) ;; => [Writer 1, "Got nuber: 1, Got nuber: 1"] (do (writer a) <- (log-number 3) (writer b) <- (log-number 5) (writer (* a b) "")) ;; EVALUATION ERROR ;; => [Writer 3, "Got nuber: 3, base"] (log-number 3) ; => [Writer 3, "Got nuber: 3"] (just 1) ; => [Just 1] (do let y = 5 (just x) <- (just 10) (just (* x y))) ;; => [Just 50] ;;; TODO ;;; '<- and 'let can't be used after '<-