write-ups-challenges-2021-2022/restrictive-racket/either.rkt
2021-12-03 00:33:26 +01:00

76 lines
1.6 KiB
Racket

#lang racket
(provide left right left? right? squash
>>= return reduce <*> e-map do)
(struct either (tag value))
(define (left val)
(either 'left val))
(define (right val)
(either 'right val))
(define (left? val)
(and (either? val) (eq? (either-tag val) 'left)))
(define (right? val)
(not (left? val)))
(define (>>= e f)
(if (eq? (either-tag e) 'left)
e
(f (either-value e))))
(define (return x)
(right x))
(define (reduce f-left f-right e)
(if (eq? (either-tag e) 'left)
(f-left (either-value e))
(f-right (either-value e))))
(define (<*> f e)
(cond
((eq? 'left (either-tag f))
f)
((eq? 'left (either-tag e))
e)
(else
(right ((either-value f) (either-value e))))))
(define (e-map f e)
(if (eq? 'left (either-tag e))
e
(right (f (either-value e)))))
(define (squash e)
(if (and (right? e) (either? (either-value e)))
(either-value e)
e))
; (do
; (<- var1 exp1)
; (exp2)
; (let var2 exp3)
; (return var2))
;
; -->
; (>>= exp1 (lambda (var1) (exp2) (let ((var2 exp3)) (return var2))))
(define-syntax (do stx)
(define (do->lambda exprs)
(define expr (car exprs))
(cond
((and (pair? expr) (eq? (car expr) '<-))
`(>>= ,(caddr expr) (lambda (,(cadr expr)) ,(do->lambda (cdr exprs)))))
((and (pair? expr) (eq? (car expr) 'let))
`(let ((,(cadr expr) ,(caddr expr))) ,(do->lambda (cdr exprs))))
((null? (cdr exprs))
expr)
(else
`(begin ,expr ,(do->lambda (cdr exprs))))))
(let* ((ast (syntax->datum stx))
(transformed (do->lambda (cdr ast))))
(datum->syntax stx transformed)))