-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrandom.el
executable file
·77 lines (63 loc) · 2.48 KB
/
random.el
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
;;; random.el --- Random selection functions -*- lexical-binding: t; -*-
;; Copyright (C) 2016 Aaron Harris
;; Author: Aaron Harris <[email protected]>
;; Keywords: lisp
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This module defines functions and macros that allow for
;; higher-level selection of random outcomes than the built-in
;; `random' primitive. These include:
;;
;; `random-dispatch'
;;
;; This macro takes (modulo some syntactic sugar) an alist
;; associating integer weights to elisp forms and randomly
;; evaluates one of the forms.
;;
;; `random-dispatch*'
;;
;; This function is just like `random-dispatch', but without the
;; syntax sugar.
;;; Code:
;;;; Random dispatch
;;==================
(defun random-dispatch* (alist)
"Evaluate a random form from ALIST.
ALIST should be an association list with integer keys. Those
keys are interpreted as weights for the random selection of a
value from the ALIST. The selected value is then evaluated as an
elisp form."
(let* ((counter (lambda (acc pair) (+ acc (car pair))))
(total (seq-reduce counter alist 0))
(roll (random total)))
(catch 'hit
(seq-reduce
(lambda (acc pair)
(setq acc (funcall counter acc pair))
(if (< roll acc)
(throw 'hit (eval (cdr pair)))
acc))
alist 0))))
(defmacro random-dispatch (&rest lists)
"Evaluate a random form from LISTS.
Each LIST should start with an integer, and the remaining
elements should be elisp forms. Interpret the integers as
weights for the random selection of one LIST, and evaluate all
forms in that LIST in order. Return the value of the last form
evaluated."
(declare (debug (&rest (sexp body))))
`(random-dispatch*
',(mapcar (lambda (list)
`(,(car list) . (progn ,@(cdr list))))
lists)))
(provide 'random)
;;; random.el ends here