I'm trying to write a function which takes a sequence of bindings and an expression and returns the result.
The sequence of bindings are formatted thus: ([:bind-type [bind-vec] ... ) where bind-type is either let or letfn. For example:
([:let [a 10 b 20]] [:letfn [(foo [x] (inc x))]] ... )
And the expression just a regular Clojure expression e.g. (foo (+ a b)) so together this example pair of inputs would yeild 31.
Currently I have this:
(defn wrap-bindings
[[[bind-type bind-vec :as binding] & rest] expr]
(if binding
(let [bind-op (case bind-type :let 'let* :letfn 'letfn*)]
`(~bind-op ~bind-vec ~(wrap-bindings rest expr)))
expr))
(defn eval-with-bindings
([bindings expr]
(eval (wrap-bindings bindings expr))))
I am not very experienced with Clojure and have been told that use of eval is generally bad practice. I do not believe that I can write this as a macro since the bindings and expression may only be given at run-time, so what I am asking is: is there a more idiomatic way of doing this?
eval is almost always not the answer though sometimes rare things happen. In this case you meet the criteria because:
since the bindings and expression may only be given at run-time
You desire arbitrary code to be input and run while the program is going
The binding forms to be used can take any data as it's input, even data from elsewhere in the program
So your existing example using eval is appropriate given the contraints of the question at least as I'm understanding it. Perhaps there is room to change the requirements to allow the expressions to be defined in advance and remove the need for eval, though if not then i'd suggest using what you have.
Related
I'm starting to learn clojure and I've stumbled upon the following, when I found myself declaring a "sum" function (for learning purposes) I wrote the following code
(def sum (fn [& args] (apply + args)))
I have understood that I defined the symbol sum as containing that fn, but why do I have to enclose the Fn in parenthesis, isn't the compiler calling that function upon definition instead of when someone is actually invoking it? Maybe it's just my imperative brain talking.
Also, what are the use cases of let? Sometimes I stumble on code that use it and other code that don't, for example on the Clojure site there's an exercise to use the OpenStream function from the Java Interop, I wrote the following code:
(defn http-get
[url]
(let [url-obj (java.net.URL. url)]
(slurp (.openStream url-obj))))
(http-get "https://www.google.com")
whilst they wrote the following on the clojure site as an answer
(defn http-get [url]
(slurp
(.openStream
(java.net.URL. url))))
Again maybe it's just my imperative brain talking, the need of having a "variable" or an "object" to store something before using it, but I quite don't understand when I should use let or when I shouldn't.
To answer both of your questions:
1.
(def sum (fn [& args] (apply + args)))
Using def here is very unorthodox. When you define a function you usually want to use defn. But since you used def you should know that def binds a name to a value. fn's return value is a function. Effectively you bound the name sum to the function returned by applying (using parenthesis which are used for application) fn.
You could have used the more traditional (defn sum [& args] (apply + args))
2.
While using let sometimes makes sense for readability (separating steps outside their nested use) it is sometimes required when you want to do something once and use it multiple times. It binds the result to a name within a specified context.
We can look at the following example and see that without let it becomes harder to write (function is for demonstration purposes):
(let [db-results (query "select * from table")] ;; note: query is not a pure function
;; do stuff with db-results
(f db-results)
;; return db-results
db-results)))
This simply re-uses a return value (db-results) from a function that you usually only want to run once - in multiple locations. So let can be used for style like the example you've given, but its also very useful for value reuse within some context.
Both def and defn define a global symbol, sort of like a global variable in Java, etc. Also, (defn xxx ...) is a (very common) shortcut for (def xxx (fn ...)). So, both versions will work exactly the same way when you run the program. Since the defn version is shorter and more explicit, that is what you will do 99% of the time.
Typing (let [xxx ...] ...) defines a local symbol, which cannot be seen by code outside of the let form, just like a local variable (block-scope) in Java, etc.
Just like Java, it is optional when to have a local variable like url-obj. It will make no difference to the running program. You must answer the question, "Which version makes my code easier to read and understand?" This part is no different than Java.
Clojure, being a Lisp dialect, inherited Lisp's homoiconicity. Homoiconicity makes metaprogramming easier, since code can be treated as data: reflection in the language (examining the program's entities at runtime) depends on a single, homogeneous structure, and it does not have to handle several different structures that would appear in a complex syntax [1].
The downside of a more homogeneous language structure is that language constructs, such as loops, nested ifs, function calls or switches, etc, are more similar to each other.
In clojure:
;; if:
(if (chunked-seq? s)
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
(cons (first s) (concat (rest s) y)))
;; function call:
(repaint (chunked-seq? s)
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
(cons (first s) (concat (rest s) y)))
The difference between the two constructs is just a word. In a non homoiconic language:
// if:
if (chunked-seq?(s))
chunk-cons(chunk-first(s), concat(chunk-rest(s), y));
else
cons(first(s), concat(rest(s), y));
// function call:
repaint(chunked-seq?(s),
chunk-cons(chunk-first(s), concat(chunk-rest(s), y)),
cons(first(s), concat(rest(s), y));
Is there a way to make these program constructs easier to identify (more conspicuous) in Clojure? Maybe some recommended code format or best practice?
Besides using an IDE that supports syntax highlighting for the different cases, no, there isn't really a way to differentiate between them in the code itself.
You could try and use formatting to differentiate between function calls and macros:
(for [a b]
[a a])
(some-func [a b] [a a])
But then that prevents you from using a one-line list comprehension using for; sometimes they can neatly fit on one line. This also prevents you from breaking up large function calls into several lines. Unless the reducing function is pre-defined, most of my calls to reduce take the form:
(reduce (fn [a b] ...)
starting-acc
coll)
There are just too many scenarios to try to limit how calls are formatted. What about more complicated macros like cond?
I think a key thing to understand is that the operation of a form depends entirely on the first symbol in the form. Instead of relying on special syntaxes to differentiate between them, train your eyes to snap to the first symbol in the form, and do a quick "lookup" in your head.
And really, there are only a few cases that need to be considered:
Special forms like if and let (actually let*). These are fundamental constructs of the language, so you will be exposed to them constantly.
I don't think these should pose a problem. Your brain should immediately know what's going on when you see if. There are so few special forms that plain memorization is the best route.
Macros with "unusual" behavior like threading macros and cond. There are still some instances where I'll be looking over someone's code, and because they're using a macro that I don't have a lot of familiarity with, it'll take me a second to figure out the flow of the code.
This is remedied though by just getting some practice with the macro. Learning a new macro extends your capabilities when writing Clojure anyway, so this should always be considered. As with special forms, there really aren't that many mind-bending macros, so memorizing the main ones (the basic threading macros, and conditional macros) is simple.
Functions. If it's not either of the above, it must be a function and follow typical function calling syntax.
Clojure and Scala both have composing functions/methods (comp and .compose respectively). Scala has a method .andThen which works the same way as .compose, except it nests the function application in the opposite order. Does an analog of this function exist in Clojure?
I could write it easily enough myself for example like this:
(defn and-then [& fns] (apply comp (reverse fns))), however it seems basic enough that it must already exist, especially since in Clojure it has natural application in converting threading-macro expressions into point-free functions, e.g. the following two expressions would be equivalent in the unary case: #(->> % a b c) and (and-then a b c)
I don't think there's anything built-in, likely because clojure does not have an infix syntax (i.e. (and-then f g) is not as clear as f andThen g). As you already recognized -> and ->> are what's generally used in it's place.
No, there is no such built-in functionality in Clojure. The code example you provided is good enough I believe.
The following two statements give the same result:
(with-monad maybe-m
(domonad [a nil
b (+ 1 a)]
b)) ;; nil
(domonad maybe-m [a nil
b (+ 1 a)]
b) ;; nil
I'm still very new to clojure and especially monads, but I was just trying to figure out what the difference is in this case.
Thanks
If you look at the definition of with-monad, you'll see that all it does is extract the meaningful functions out of the monad given as the first argument.
domonad is a "syntactic suger" to let you write monadic operations without manually binding and returning. it actually uses with-monad internally to evaluate the exprs using the monads meaningful functions.
if you call domonad with only two parameters, as you did in your first example, it assumes you are already in a context of a monad, meaning that all the meaningful functions are available. in your first example, they are indeed available because you made them available by using with-monad before the call. OTOH, if you call it with three arguments, as in your second example, it first introduces the context of the monad using with-monad, and then proceeds to evaluate the binding.
So in essence, these two samples are exactly the same.
This question similar to say, In clojure, how to apply 'and' to a list?, but solution doesn't apply to my question. every? function returns just a boolean value.
or is a macro, so this code is invalid:
(apply or [nil 10 20]) ; I want to get 10 here, as if 'or was a function.
Using not-every? I will get just boolean value, but I want to preserve semantics of or - the "true" element should be a value of the expression. What is idiomatic way to do this?
My idea so far:
(first (drop-while not [nil 10 20])) ; = 10
you might be able to use some for this:
(some identity [nil 10 20]) ; = 10
Note that this differs from or if it fails
(some identity [false]) ; = nil
(or false) ; = false
A simple macro:
(defmacro apply-or
[coll]
`(or ~#coll))
Or even more abstract
(defmacro apply-macro
[macro coll]
`(~macro ~#coll))
EDIT: Since you complained about that not working in runtime here comes a version of apply-macro that works in runtime. Compare it with answers posted here: In clojure, how to apply a macro to a list?
(defmacro apply-macro-in-runtime
[m c]
`(eval (concat '(~m) ~c)))
Notice that this version utilizes that parameters are passed unevaluated (m is not evaluated, if this was a function, it would throw because a macro doesn't have a value) it uses concat to build a list containing of a list with the quoted macro-name and whatever the evaluation of form c (for coll) returns so that c as (range 5) would be fully evaluated to the list that range returns. Finally it uses eval to evaluate the expression.
Clarification: That obviously uses eval which causes overhead. But notice that eval was also used in the answer linked above.
Also this does not work with large sequences due to the recursive definition of or. It is just good to know that it is possible.
Also for runtime sequences it makes obviously more sense to use some and every?.