racket-algebraic icon indicating copy to clipboard operation
racket-algebraic copied to clipboard

Cannot define the writer monad

Open Tuplanolla opened this issue 1 year ago • 0 comments

I tried to define the writer monad with an arbitrary monoid as the accumulator, but could not figure out how to express the necessary class constraint. The following program raises the error writer.rkt:46:45: <>: no instance for semigroup even though it should produce the value (list (list "first" "third" "second" "fourth") 62). Is this a limitation of the library or my own mistake?

#lang algebraic/racket/base

(require racket/match)
(require algebraic/control/applicative)
(require algebraic/control/monad)
(require algebraic/data/functor)
(require algebraic/data/list)
(require algebraic/data/monoid)
(require algebraic/data/semigroup)

(define (tell s)
  (list s (void)))

(define (listen a)
  (match a
    ((list s x) (list s (list s x)))))

(define (pass p)
  (match p
    ((list s (list f x)) (list (f s) x))))

(define-syntax writer-functor
  (instance functor
    (fmap (lambda (f a)
            (match a
              ((list s x) (list s (f x))))))))

(define-syntax writer-applicative
  (instance applicative
    extends (writer-functor)
    (pure (lambda (x) (list mempty x)))
    (<*> (lambda (p a)
           (match p
             ((list s f) (match a
                           ((list t x) (list (<> s t) (f x))))))))))

(define-syntax writer-monad
  (instance monad
    extends (writer-applicative)
    (>>= (lambda (a k)
           (match a
             ((list s x) (match (k x)
                           ((list t y) (list (<> s t) y)))))))))

(with-instances (list-monoid writer-monad)
  (>>= (pure 42) (lambda (x)
  (>>M (tell (list "first"))
  (>>= (pure 13) (lambda (y)
  (>>= (pass (>>M (tell (list "second"))
             (>>M (tell (list "third"))
             (pure (list reverse 7))))) (lambda (z)
  (>>M (tell (list "fourth"))
  (pure (+ x y z)))))))))))

Tuplanolla avatar May 26 '23 18:05 Tuplanolla