samppi a écrit :
> I tried asking about this yesterday, but it seems like I expressed my
> problem poorly. Anyways, here's another shot. :)
>
> (declare value)
>
> (def array (conc array-start value array-sep value array-end))
>
> (def value (alt array bit))
>
You can get your code to work by writing:
(declare value)
(def array (conc array-start #'value array-sep #'value array-end))
(def value (alt array bit))
#'value introduces an indirection by returning the var and not the
functions (and a var proxies calls to its current value) but this
indirection is mutable.
You can also try to use delays:
(defn conc [& subrules]
(fn [tokens]
(loop [subrule-queue (map force subrules), remaining-tokens (seq
tokens), products []] ; force (potentially) delayed rules
(if (nil? subrule-queue)
[products remaining-tokens]
(let [[subrule-products subrule-remainder :as subrule-result]
((first subrule-queue) remaining-tokens)]
(when-not (nil? subrule-result)
(recur (rest subrule-queue) subrule-remainder
(conj products subrule-products))))))))
(defn alt [& subrules]
(fn [tokens]
(some #((force %) tokens) subrules))) ; added force
Here a subrule is either a function or a delay on a function:
(declare value)
(def array (delay (conc array-start value array-sep value array-end)))
(def value (alt array bit))
samppi=> (value (seq "[0,0]"))
[[\[ \0 \, \0 \]] nil]
samppi=> (array (seq "[0,0]"))
java.lang.ClassCastException: clojure.lang.Delay cannot be cast to
clojure.lang.IFn (NO_SOURCE_FILE:0)
samppi=> ((force array) (seq "[0,0]"))
[[\[ \0 \, \0 \]] nil]
You may have to write a "call-rule" helper function to force the rule
before calling it.
But, without resorting to macros, You can also do:
(defn conc [tokens & subrules]
(loop [subrule-queue (seq subrules), remaining-tokens (seq tokens),
products []]
(if (nil? subrule-queue)
[products remaining-tokens]
(let [[subrule-products subrule-remainder :as subrule-result]
((first subrule-queue) remaining-tokens)]
(when-not (nil? subrule-result)
(recur (rest subrule-queue) subrule-remainder
(conj products subrule-products)))))))
(defn alt [tokens & subrules]
(some #(% tokens) subrules))
(declare value)
(defn array [tokens]
(conc tokens array-start value array-sep value array-end))
(defn value [tokens]
(alt tokens array bit))
(But really it's what a macro should produce :-()
Hope this help.
Christophe
--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)
and you don't need the call-rule helper.
Yup, elaborating on my third option:
(defn conc* [tokens & subrules]
(loop [subrule-queue (seq subrules), remaining-tokens (seq tokens),
products []]
(if (nil? subrule-queue)
[products remaining-tokens]
(let [[subrule-products subrule-remainder :as subrule-result]
((first subrule-queue) remaining-tokens)]
(when-not (nil? subrule-result)
(recur (rest subrule-queue) subrule-remainder
(conj products subrule-products)))))))
(defn alt* [tokens & subrules]
(some #(% tokens) subrules))
(defmacro conc [& subrules]
`(fn [tokens#]
(conc* tokens# ~@subrules)))
(defmacro alt [& subrules]
`(fn [tokens#]
(alt* tokens# ~@subrules)))
(declare value)
(def array (conc array-start value array-sep value array-end))
(def value (alt array bit))
Christophe