blob: 471e7568c547c2a580bc3bea1204d094cda74598 (
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
(define-module (monad state)
#:use-module (oop goops)
#:use-module (ice-9 match)
#:use-module (monad)
#:export (return-state run-state get put modify)
#:re-export (>>= >> fmap return))
;; Alternative implementation of get.
;; See https://hackage.haskell.org/package/mtl-2.2.1/docs/src/Control.Monad.State.Class.html#get
;;; newtype State = st-list -> st-list
;;; state procedure <=> st-list -> st-list
;;; state list <=> (list ret st)
;;; Wrapper around a procedure with signature:
;;; (st-list -> st-list). Wrapped to allow goops
;;; multiple dispatch to do its thing.
(define-class <state> ()
(proc #:init-keyword #:proc
#:getter proc))
;; (st-list -> st-list) -> State
(define (make-state proc)
"Creates a state object from a State procedure"
(make <state> #:proc proc))
;;; Define a procedure which is in the state monad. This means that it takes a
;;; state list as a curried argument, and it's return is wrappen in a <state>
;;; object.
;;; It's fully possible to create stateful objects without these macros, but it's
;;; ill adviced since that would just be boilerplate.
(define-syntax-rule (define-stateful ((proc args ...) st) body ...)
(define (proc args ...)
(make-state
(lambda (st) body ...))))
(define-syntax-rule (define-stateful-method ((proc args ...) st) body ...)
(define-method (proc args ...)
(make-state
(lambda (st) body ...))))
(define-stateful-method ((>>= (st <state>) (f <procedure>)) st-list)
(let ((new-st-list ((proc st) st-list)))
(match new-st-list
((v _)
((proc (f v)) new-st-list)))))
;; (define-stateful-method ((>> (a <state>) (b <state>)) st-list-a)
;; (let ((st-list-b ((proc a) st-list-a)))
;; ((proc b) st-list-b)))
(define-stateful ((return-state v) st-list)
"Sets the return value to v"
(cons v (cdr st-list)))
(define-method (return (a <state>)) return-state)
(define-stateful ((get) st-list)
"Sets the return value of state to st."
(match st-list
((_ st)
(list st st))))
(define-stateful ((put v) st-list)
"Sets st to v."
(list '() v))
(define-stateful ((modify proc) st-list)
(match st-list
((r s)
(list '() (proc s)))))
;; (define-stateful-method ((fmap (f <procedure>) (s <state>)) st-list)
;; (match ((proc s) st-list)
;; ((r st)
;; (list (f r) st))))
(define-method (run-state (st <state>) init)
"Exec state with init as starting state value and st."
((proc st) (list init init)))
|