mice 0.11.1

messing with dice
Documentation
;;; A core library of MIR functions, in a Lisp-like language.
;;;
;;; The idea here is to permit declaring the bulk of the code for
;;; operators as functions in a more convenient language than
;;; the verbose "declare node; declare node; declare edge; ..." process
;;; we're doing now.
;;;
;;; We do this with the goal of laying the ground work for a user-facing
;;; scripting language to be provided at some point in the future.
;;; A scripting language in which a user can provide their own user defined
;;; operators, whose output will be formatted according to the user's whims(?).
;;;
;;; That future language will likely not be a Lisp, but it will have the same
;;; semantics and scoping rules.
;;; That future language will also likely have type inference on signatures,
;;; but this one will not.
;;; That future language may not expose the full set of MIR node types directly,
;;; but this one will, so that we can experiment with them.

;; MIR nodes are capitalized.

;; Currently, the available output annotations are provided by the compiler.
;; I do not have reason to believe that will change, as the runtime must be aware
;; of every possible annotation in order to be able to produce formatted output,
;; regardless of what this code does.
;; Making MIR code handle formatting as well would be tricky, and require adding
;; many features to the language that are orthogonal to rolling dice.

;; Relevant optimizations:
;; - Constant propagation
(defun roll ((count i64) (sides i64))
  (-> (MSet i64) Intermediates)
  (let* ((result (Roll count sides))
        (annotation (Annotate result (Annotation::Roll count sides))))
    (return result annotation)))

;; Relevant optimizations:
;; - Constant propagation
;; - Function inlining
;; - Reference elision (erase reference values in favor of static stack offsets)
(defun simple_filter ((count i64) (sides i64) (keep_count i64) (kind i64))
  (-> (MSet i64) Intermediates)
  (let* ((initial (roll count sides))
         (filtered (Decision kind
                             (0 (KeepHigh keep_count &initial))
                             (1 (KeepLow keep_count &initial))
                             (2 (DropHigh (- count keep_count) &initial))
                             (3 (DropLow (- count keep_count) &initial)))))
    (PushToList initial &list)
    (PushToList filtered &list)
    (return filtered (Annotate list (Decision kind
                                              (0 (Annotation::KeepHigh keep_count))
                                              (1 (Annotation::KeepLow keep_count))
                                              (2 (Annotation::DropHigh (- count keep_count)))
                                              (3 (Annotation::DropLow (- count keep_count))))))))

;; Relevant optimizations:
;; - Constant propagation
;; - Loop fusion (Summate + FilterSatisfies)
;; - Intermediate result elision (FilterSatisfies -> Count)
;; - Possibly devectorization, if we keep the vectorized nodes and they
;;   get in the way of the above two optimizations
;; - Reference elision (erase reference values in favor of static stack offsets)
(defun explode ((count i64) (sides i64))
  (-> i64 Intermediates)
  (let ((iterations (MakeList))
        (sum 0)
        (remaining_count count))
    (do
     (UseFuel (saturating_mul count 4))
     (let ((iteration (Roll remaining_count sides)))
       ;; TODO: implement references so I can do this without cloning `iteration`
       (+= sum (Summate &iteration))
       (PushToList iteration &iterations)
       ;; TODO: implement closure captures in MIR so we can actually do this
       (set remaining_count (Count (FilterSatisfies iteration (lambda ((die i64)) (eq die sides))))))
     (while (> remaining_count 0)))
    (let ((intermediate (Annotate iterations (Annotation::Explode count sides))))
      (return sum intermediate))))


;; Relevant optimizations:
;; - Constant propagation
;; - Function inlining
;; - Loop invariant code motion
(defun filter_satisfies ((predicate (Function i64 -> bool))
                         (dice (MSet i64)))
  (-> (MSet i64))
  (if (> (Length dice) 0)
      (let ((idx 0))
        (do
         (if (not (predicate (index idx dice)))
             (SwapRemove idx dice))
         (while (> (Length dice) idx)))
        dice)
      dice))