27 lines
1.2 KiB
Clojure
27 lines
1.2 KiB
Clojure
(defn tape
|
|
"Creates a new tape with given blank character and tape contents"
|
|
([blank] (tape () blank () blank))
|
|
([right blank] (tape () (first right) (rest right) blank))
|
|
([left head right blank] [(reverse left) (or head blank) (into () right) blank]))
|
|
|
|
; Tape operations
|
|
(defn- left [[[l & ls] _ rs b] c] [ls (or l b) (conj rs c) b])
|
|
(defn- right [[ls _ [r & rs] b] c] [(conj ls c) (or r b) rs b])
|
|
(defn- stay [[ls _ rs b] c] [ls c rs b])
|
|
(defn- head [[_ c _ b]] (or c b))
|
|
(defn- pretty [[ls c rs b]] (concat (reverse ls) [[(or c b)]] rs))
|
|
|
|
(defn new-machine
|
|
"Returns a function that takes a tape as input, and returns the tape
|
|
after running the machine specified in `machine`."
|
|
[machine]
|
|
(let [rules (into {} (for [[s c c' a s'] (:rules machine)]
|
|
[[s c] [c' (-> a name symbol resolve) s']]))
|
|
finished? (into #{} (:terminating machine))]
|
|
(fn [input-tape]
|
|
(loop [state (:initial machine) tape input-tape]
|
|
(if (finished? state)
|
|
(pretty tape)
|
|
(let [[out action new-state] (get rules [state (head tape)])]
|
|
(recur new-state (action tape out))))))))
|