This repository has been archived by the owner on Mar 30, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
monad.rkt
62 lines (47 loc) · 1.75 KB
/
monad.rkt
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#lang racket/base
; Limited monad library with monomorphic bind and related do notation
(provide (all-defined-out))
(require (for-syntax racket/base
syntax/parse)
racket/generic)
(define-generics monad
[bind monad continue])
(define-syntax (:= stx)
(raise-syntax-error #f ":= outside mcompose" stx))
(define-syntax (mdo stx)
(syntax-parse stx #:literals (:=)
[(_) #'(void)]
[(_ e:expr) #'e]
[(_ target:id := e:expr . body)
#'(bind e (λ (target) (mdo . body)))]
[(_ e:expr . body)
#'(bind e (λ _ (mdo . body)))]))
(module+ test
(require racket/function
rackunit)
(struct include-string (proc)
#:methods gen:monad
[(define (bind ma f) (include-string-bind ma f))])
(define (include-string-bind ma f)
(include-string
(λ (str)
(define-values (v str*) ((include-string-proc ma) str))
(define-values (v* str**) ((include-string-proc (f v)) str*))
(values v* str**))))
(define (include-string-return v)
(include-string (curry values v)))
(define program
(mdo a := (include-string-return 1)
b := (include-string (λ (str) (values (add1 a) (string-append str "+"))))
(include-string (λ (str) (values (* b 2) (string-append str "*"))))))
(test-pred "Allow empty (mdo) forms"
void?
(mdo))
(test-pred "Adopts value of monadic type using mdo"
include-string?
program)
(test-case "Compose operations with mdo"
(call-with-values (λ () ((include-string-proc program) "start"))
(λ (v str)
(check-equal? v 4)
(check-equal? str "start+*")))))