When I try to add metadata to an infinite lazy sequence in Clojure, I get a stack overflow, and if I take off the metadata, then it works just fine. Why does adding the with-meta macro break the lazy seq?
First create an infinite seq of a very nice number:
(defn good []
(lazy-seq
(cons 42
(good))))
user> (take 5 (good))
(42 42 42 42 42)
Then, add some metadata to each of the lazy-seq instances:
(defn bad []
(lazy-seq
(cons 42
(with-meta
(bad)
{:padding 4}))))
user> (take 5 (bad))
java.lang.StackOverflowError (NO_SOURCE_FILE:0)
[Thrown class clojure.lang.Compiler$CompilerException]
Try moving the meta data up one level:
(defn also-bad []
(with-meta
(lazy-seq
(cons 42
(also-bad)))
{:padding 4}))
user> (take 5 (foo))
java.lang.StackOverflowError (NO_SOURCE_FILE:0)
[Thrown class clojure.lang.Compiler$CompilerException]
Here is an example of meta data on a finite sequence:
(defn also-works []
(lazy-seq
(cons 4
(with-meta
()
{:a 5}))))
user> (also-works)
(4)
user> (meta (rest (also-works)))
{:a 5}
user>
Because a LazySeq evaluates its body as soon as you call withMeta on the LazySeq. You lose your laziness.
public final class LazySeq extends Obj implements ISeq, List{
...
public Obj withMeta(IPersistentMap meta){
return new LazySeq(meta, seq());
}
...
}
seq() evaluates the lazy seq's body if it hasn't already been evaluated. Your code above keeps calling with-meta on successive lazy seqs, which evaluates them all until the stack explodes. I don't think there's currently any way to add metadata to a lazy seq without causing it to evaluate its body.
Related
I am trying to define a class method like so:
#lang racket
(define foo% (class object%
(super-new)
(define/public plus-one (curry + 1))))
But this code produces the following error:
eval:2:0: class: bad form for method definition
According to the Racket documentation, it should be possible to define a method using the syntax (define/public id expr), so I don't understand why this isn't working.
There is an easy workaround by using the (define/public (id . formals) body ...+) syntax, of course, but I would like to understand why the current code isn't accepted.
In the documentation for class*, see the nonterminals named method-definition and method-procedure. They describe the constraints on a legal method definition. A paragraph later in the class docs says that each private, public, etc declaration must correspond to a method-definition. So it isn't a bug, it's the intended behavior.
The reason behind the behavior, by the way, is that Racket's class macro implements methods by rewriting the method's lambda (or case-lambda) expression(s) to add an implicit argument for this. The same argument is also implicitly used to access the object's public and private fields. Restricting method definitions to certain shapes makes it possible to find the right lambda expressions to adjust.
Here's one way of rewriting your example:
#lang racket
(define do-plus-one (curry + 1))
(define foo% (class object%
(super-new)
(define/public (plus-one n) (do-plus-one n)))
This has the following nice properties: do-plus-one is computed only once, and it doesn't take a field slot in each foo% object.
It might be a bug. Imagine we have the usuall way:
(define/public (plus-one n) (+ 1 n))
The define way with name and arguments in parentheses are sugar for a id and lambda and that works:
(define/public plus-one (lambda (n) (+ 1 n)))
I'm getting that (curry + 1) returns a similar lambda and that that object should be working, but it isn't.
The whole point with a class method is using the private fields from the object and none of them do that, however only curry version makes it obvious that it will not be able to since the resulting procedure won't be having the scope of the object.
If you imagined we used a private variable for the increment you couldn't use curry since it would cache it. eg. you can't replicate this:
(define increaser%
(class object%
(init inc)
(define increment inc)
(super-new)
(define/public (set-inc inc)
(set! increment inc))
(define/public (increase n)
(+ increment n))))
(define test (new increaser% [inc 2]))
(send test increase 1) ; ==> 3
(send test set-inc 3)
(send test increase 1) ; ==> 4
(define test2 (new increaser% [inc 21]))
(define value 13)
(map (lambda (obj) (send obj increase value)) (list test test2))
; ==> (16 34)
Most of my application state is stored in a large complex map. For the purposes of this question, I will use a simple structure:
(def data
{:a 1
:b {:c {:d 3}}})
I have a large number of functions which all follow the same pattern:
(defn update-map
[my-map val]
(let [a (:a my-map)
d (-> my-map :b :c :d)]
(assoc-in
(assoc my-map :a (+ a val))
[:b :c :d] (+ d val))))
I retrieve one or more values from the map, perform some calculations, and create a new map with updated values. There are two problems with this approach:
I have a lot of repetitive let bindings across different function definitions
If the schema of the map changes, I will have a lot of code to refactor
I've written a macro to reduce the boilerplate code required to define these functions. It works by looking up predefined getter and setter functions, and automatically generating a let block:
(def getters
{'a #(:a %)
'd #(-> % :b :c :d)})
(def setters
{'a #(assoc % :a %2)
'd #(assoc-in % [:b :c :d] %2)})
(defmacro def-map-fn
[name [& args] [& fields] & code]
(let [my-map 'my-map
lookup #(reduce % [] fields)
getter-funcs (lookup #(conj % %2 (list (getters %2) my-map)))
setter-funcs (lookup #(conj % (symbol (str "update-" %2)) (setters %2)))]
`(defn ~name [~my-map ~#args]
(let [~#getter-funcs ~#setter-funcs]
~#code))))
I can now define my functions more elegantly:
(def-map-fn update-map
[val] ; normal function parameters
[a d] ; fields from the map I will be using
(update-d
(update-a my-map (+ a val))
(+ d val)))
When expanded, it will produce a function definition looking something like this:
(defn update-map
[my-map val]
(let [a (#(:a %) my-map)
d (#(-> % :b :c :d) my-map)
update-a #(assoc % :a %2)
update-d #(assoc-in % [:b :c :d] %2)]
(update-d
(update-a my-map (+ a val))
(+ d val))))
One thing that is nagging me about my macro is that it is not intuitive to the programmer that the my-map function parameter is available for use within the function body.
Is this a good use of macros, or should I be using a different approach entirely (like dynamic var bindings)?
You could perhaps use lenses; the getters and setters then become composable functions. Have a look here or here.
Following the first link you can set up the lens as follows:
; We only need three fns that know the structure of a lens.
(defn lens [focus fmap] {:focus focus :fmap fmap})
(defn view [x {:keys [focus]}] (focus x))
(defn update [x {:keys [fmap]} f] (fmap f x))
; The identity lens.
(defn fapply [f x] (f x))
(def id (lens identity fapply))
; Setting can be easily defined in terms of update.
(defn put [x l value] (update x l (constantly value)))
(-> 3 (view id))
; 3
(-> 3 (update id inc))
; 4
(-> 3 (put id 7))
; 7
; in makes it easy to define lenses based on paths.
(defn in [path]
(lens
(fn [x] (get-in x path))
(fn [f x] (update-in x path f))))
(-> {:value 3} (view (in [:value])))
; 3
(-> {:value 3} (update (in [:value]) inc))
; {:value 4}
(-> {:value 3} (put (in [:value]) 7))
; {:value 7}
You can see form the above the the lens can be adapted to use get/set methods (such as get-in/update-in) based on the data structure you are working with. The real power of lenses which seems to also be what you are after is that you can compose them. In the same example the composition function can be defined as follows:
(defn combine [outer inner]
(lens
(fn [x] (-> x (view outer) (view inner)))
(fn [f x] (update x outer #(update % inner f)))))
(defn => [& lenses] (reduce combine lenses))
The => function can now be used to combine any arbitrary lenses such as:
(-> {:new {:value 3}} (view (=> (in [:new]) (in [:value]))))
; 3
(-> {:new {:value 3}} (update (=> (in [:new]) (in [:value])) inc))
; {:new {:value 4}}
(-> {:new {:value 3}} (put (=> (in [:new]) (in [:value])) 7))
; {:new {:value 7}}
The fact that (in [:new]) is just a function means that you could, for example, store it and manipulate it in various ways. For example, it would be possible to walk your nested map structure and create the lens functions which correspond to accessing the value at each level in the nested map and then at the end compose these functions together to create your getter/setter api. With this set up, your lenses could automatically adapt to any changes in your schema.
The ability to compose lenses can also make it easy to interact with the nodes of your nested map. For example, if you were to ever change the node from an atom to a list, you could simply add a new lens to work with it as follows:
(def each (lens seq map))
(-> {:values [3 4 5]} (view (=> (in [:values]) each)))
; (3 4 5)
(-> {:values [3 4 5]} (update (=> (in [:values]) each) inc))
; {:values (4 5 6)}
(-> {:values [3 4 5]} (put (=> (in [:values]) each) 7))
; {:values (7 7 7)}
I highly recommend looking at the full gist to see more examples of what you can do with lenses.
In this situation, my preference is to avoid the use of macros. They often obfuscate code, but more importantly they aren't composable. An ideal solution here would allow you to use the getter and setter functions outside of functions being defined in def-map-fn. I'd stick with regular functions and data as much as possible.
To begin with, you're concerned about having to rewrite a bunch of code if your schema changes. Fair enough. To address that, I'd start with a data representation of your map's schema. See Prismatic schema for a full-featured schema library for Clojure, but for now something along these lines should do:
(def my-schema
{:a :int
:b {:c {:d :int}}})
From this, you can compute the paths for all the properties in your schema:
(defn paths [m]
(mapcat (fn [[k v]]
(conj (if (map? v)
(map (partial apply vector k) (paths v)))
[k]))
m))
(def property-paths
(into {} (for [path (paths my-schema)] [(last path) path])))
Now, to get or set a property, you can look up its path and use that in conjunction with get-in, update-in, etc. as appropriate:
(let [d (get-in my-map (property-paths :d))]
;; Do something with d.
)
If you get tired of always calling get-in, assoc-in, etc., then you can pretty easily generate a bunch of getter functions:
(doseq [[p path] property-paths]
(eval `(defn ~(symbol (str "get-" (name p)))
[m#] (get-in m# ~path))))
(doseq [[p path] property-paths]
(eval `(defn ~(symbol (str "set-" (name p)))
[m# v#] (assoc-in m# ~path v#))))
(doseq [[p path] property-paths]
(eval `(defn ~(symbol (str "update-" (name p)))
[m# tail#] (apply update-in m# ~path #tail))))
Now you have your get-a, set-a, update-a functions available everywhere in your code, without having to call into some uber-macro to set up the bindings for you. For instance:
(let [a (get-a my-map)]
(-> my-map
(set-a 42)
(update-d + a)))
If you really find setting up the above let binding tedious, you could even write a with-properties macro that accepts a map and a list of property names and executes the body in a context that binds values for those names. But I probably wouldn't bother.
Advantages of this approach include:
It's schema-driven, so the schema is defined in one central place and used to generate other code as needed.
It prefers pure functions over macros, so code is more re-usable and composable.
It's an incremental approach that allows your application to grow more naturally. Rather than starting with an uber-macro that tries to anticipate all possible features you might want, you start with data and functions and sprinkle in macros to alleviate some of the repetitiveness as you see usage patterns emerge.
Why don't you just use update-in?
(defn update-map [my-map val]
(-> my-map
(update-in [:a] + val)
(update-in [:b :c :d] + val)))
I'm trying to generator fn through macro.But I meet a strange issue.
Code is Here.
(defmacro test2 [lmk]
(fn [lmk2] (println lmk lmk2)))
((test2 12) 13) ;;----->Error
(defmacro test3 []
(fn [lmk] (println lmk)))
((test3) 12) ;;----->OK
(defmacro test4 []
`(fn [lmk] (println lmk)))
((test4) 12) ;;----->Error
I know defn can work well.I just want to know why I can't use defmacro here.And why test3 works well,however test2 fails.
In test2, prior to compilation, the test2 macro will be invoked (lmk has not yet been compiled or evaluated) - because there is no syntax quote, this will actually evaluate the fn form and return a function object (with lmk closed over). So you then have the form (fn-object 13) passed to the compiler, which I think is going down an unexpected path (not sure exactly what that is). Interestingly this works:
(def f (test2 12))
(f 13)
In test4, the syntax quote will cause each lmk symbol to be resolved in the namespace so that's the source of that error. You really want autogensyming on those:
(defmacro test4 []
`(fn [lmk#] (println lmk#)))
In Clojure, how do I make a library macro which processes supplied functions metadata and return some result? Amount of functions is unlimited and they should be passed without being boxed into a sequence ((my-macro fn1 fn2) instead of (my-macro [fn1 fn2]))
Say, we expect function vars having :foo keys in meta and the macro concatenates their values. The following snippet should work in REPL (considering my-macro is in the namespace):
user=> (defn my-func-1 {:foo "bar"} [])
(defn my-func-1 {:foo "bar"} [])
#'user/my-func-1
user=> (defn my-func-2 {:foo "baz"} [])
(defn my-func-2 {:foo "baz"} [])
#'user/my-func-2
user=> (my-macro my-func-1 my-func2)
(my-macro my-func-1 my-func2)
"barbaz"
I tried several approaches but was only able to process single function so far.
Thanks!
Try this:
(defmacro my-macro [& fns]
`(clojure.string/join (list ~#(map (fn [x] `(:foo (meta (var ~x)))) fns))))
(defn ^{:foo "bar"} my-func-1 [])
(defn ^{:foo "baz"} my-func-2 [])
(my-macro my-func-1 my-func-2) ;; => "barbaz"
How it Works
If you expand the macro you can start to see the parts in play.
(macroexpand '(my-macro my-func-1 my-func-2))
(clojure.string/join
(clojure.core/list (:foo (clojure.core/meta (var my-func-1)))
(:foo (clojure.core/meta (var my-func-2)))))
(var my-func-1)
Function metadata is stored on the var, so using (meta my-func-1) is not sufficient. But, var is a special form and does not compose like a normal function.
(fn [x] `(:foo (meta (var ~x))))
This anonymous function exists inside an escaped form, so it is processed inside the macro to produce the output forms. Internally it will create a the (:foo (meta (var my-func-1))) form by first backtick escaping the outer form to declare it a literal, and not evaluated, list and then unescaping the x var with a tilde to output the value instead of the symbol.
`(clojure.string/join (list ~#(map (fn [x] `(:foo (meta (var ~x))))
fns)))
This entire form is backtick escaped, so it will be returned literally. But, I still need to evaluate the map function generating the (:foo (meta (var my-func-1))) form. In this case I have unescaped, and spliced (#) the result of, the map form directly. This first evaluates the map function and returns a list of generated forms, and then takes the contents of that list and splices it into the parent list.
(defmacro test1 [x] `(~x))
(defmacro test2 [x] `(~#x))
(macroexpand '(test1 (1 2 3))) ;; => ((1 2 3))
(macroexpand '(test2 (1 2 3))) ;; => (1 2 3)
You could also split out the map function in a let statement before hand for slightly more readability.
(defmacro my-macro [& fns]
(let [metacalls (map (fn [x] `(:foo (meta (var ~x)))) fns)]
`(clojure.string/join (list ~#metacalls))))
Ok, let's try to get this straight: my final intent is to provide a macro as an API to users which will look like:
(defscript [a b]
(println a))
The result has to be an instance of a Script protocol, which looks like:
(defprotocol Script
(run [this model]))
The idea being that the first argument to defscript is a list of symbols that needs to be bound to correspondent keys in the model:
(.run (defscript [a b] (println a)) {:a 1}) ;; yields 1
I can't come up with any code that can effectively produce such effect, as I'm constantly hitting a wall when trying to use the model parameter, since at macro expansion time it's just a symbol:
(defmacro invoke-
[params model body]
(let [p (flatten (map (fn [x] [x (model (keyword x))]) params))]
`(let [~#p]
~body)))
(defmacro defscript
[params & body]
`(reify Script
(run [~'this ~'model]
(invoke- ~params ~'model ~#body))))
invoke- works fine if called directly:
(invoke- [a] {:a 1} (println a)) ;; prints 1
but it doesn't work when used within defscript as model can't be expanded correctly:
(.run (defscript [a] (println a)) {:a 1}) ;; prints nil
How can I get past this point and glue the pieces together?
It seems that basically, your argument vector is a shortcut for a destructuring binding:
(defscript [a b] body) -> (reify Script (run [this {:keys [a b]}] body))
That way, model is destructured at run time, as it should be.