Clojure macro to allow writing code without let bindings - clojure

I am trying to write a macro that will allow me to do the following
(without-nesting
(:= x 1)
(:= y 2)
(:= z 3)
(db-call x y z)
(:= p 33)
(db-call x y z p))
becomes
(let [x 1
y 2
z 3]
(db-call x y z)
(let [p 33]
(db-call x y z p)))
So far my implementation has been the following
(defn assignment?
[[s _]]
(= s ':=))
(defmacro without-nesting
[& body]
(let [[bindings xs] (split-with assignment? body)
[non-bindings remaining] (split-with (complement assignment?) xs)]
`(let [~#(mapcat rest bindings)]
~#non-bindings
~(when (seq remaining)
`(without-nesting ~#remaining)))))
I'm having issues when remaining is going to be empty. In my current implementation a nil gets placed which prevents the last form in non-bindings to return its value. I have no clue on how to proceed with a recursive macro. Can someone help
UPDATE:
So I was able to get rid of the nil but I just want to know if there's a better way to deal with this
(defmacro without-nesting
[& body]
(let [[bindings xs] (split-with assignment? body)
[non-bindings remaining] (split-with (complement assignment?) xs)]
`(let [~#(mapcat rest bindings)]
~#non-bindings
~#(if (seq remaining)
[`(without-nesting ~#remaining)]
[]))))
Also would this be a good way to write code? Or do you see any caveats? For me it looks more linear as compared to nested let
I do see how ppl may abuse this. In the case of let, if the nesting becomes too much, then it's a hint to refactor the code. This might hide that

Just use let. It is already recursive. To incorporate function calls where you only care about the side effects, the convention is to bind to an underscore.
(let [x 1
y 2
z 3
_ (db-call x y z)
p 33
_ (db-call x y z p)])

Related

How can I iterate over items from two different lists in Clojure in lockstep?

I have two lists in clojure a and b that have the same length. I want to do the following
for i in range(len(a)):
if a[i] == b[i]:
do_something(a[i], b[i])
What I have tried but hasn't worked. for doesn't iterate over corresponding elements but all possible combinations:
(for [i a j b] (do-something i j))
An idiomatic equivalent might be:
(doall (map do-something a b))
...or, as an expanded version of that that still has you writing your own loop:
(doseq [[i j] (map vector a b)]
(do-something i j))
Because for is lazy, it may not actually evaluate your whole sequence unless something is consuming its result; doseq always calls do-something on everything.
map somefunc arg1 arg2 calls somefunc with each set of values in arg1 and arg2, exactly what you're looking for here.
A more direct translation might look like:
(doseq [i (range (count a))]
(do-something (nth a i) (nth b i)))
...but don't use that; both count and nth can be slow or unavailable, depending on the specific collection types in use.
Add the "if" condition in the loop:
(doseq [[x y] (map vector a b)
:when (= x y)]
(do_something x y))
If you would like to use a convenience function, I already have one that does this:
(ns tst.demo.core
(:use tupelo.test)
(:require [tupelo.core :as t]))
(let [xs [ 1 2 3]
ys [10 20 30]]
(is= [11 22 33]
(t/map-let [x xs
y ys]
(+ x y))))
So you write the bindings to x and y like a let form, but then it operates on the local "variables" as if in a mapv.

Loop destructuring in Clojure

Is there a way for destructuring the recur bindings in a loop?
So for example if i want to let y stay unchanged in
(loop [x 1 y 1] (if (< x 5) (recur (inc x) _ ) (println "result:" x y))
I know this is not possible, but how could i get a similar thing like _ in sequential destructuring for recur?
Assuming y never changes inside the loop, you can just wrap everything in a let that binds a value to y, or even place your loop in a function that receives y as an argument.
let
(let [y 1]
(loop [x 1]
(if (< x 5)
(recur (inc x))
(println "result:" x y)))
defn
(defn loop-with [y]
(loop [x 1]
(if (< x 5)
(recur (inc x))
(println "result:" x y)))

Does projecting in two directions count as relational in core.logic?

I understand that project in core.logic is not relational.
However, it seems that I can get relational-like behaviour by projecting in both directions inside conda, e.g.:
(defn lifto-with-inverse
"Lifts a unary function and its inverse into a core.logic relation."
([f g]
(fn [& vs]
(let [[x y] vs]
(conda
[(pred x number?) (project [x] (== y (f x)))]
[(pred y number?) (project [y] (== x (g y)))])))))
(let [inco (lifto-with-inverse inc dec)]
(run* [q] (inco q 3)))
=> 2
Does this count as a relational operation? Or is there something else missing that makes this non-relational?
It still seems like in this case one of the arguments must be ground making it non-relational.

How to increment by a number in Clojure?

I would like to know how to increment by X amount a number, in other languages I used to do
foo += 0.1;
but I have not idea how it can be done in Clojure
Variables are immutable in Clojure. So you should not try to change the value of foo, but instead, "create" a new foo:
(def foo2 (+ foo 0.1))
...or, if in a loop, recur with a new value:
(loop [foo 5.0]
(when (< foo 9)
(recur (+ foo 0.1))))
...or, if foo is an atom, swap! it with a new value:
(def foo (atom 5.0))
(swap! foo (partial + 0.1))
I recommend you start by reading the rationale of Clojure.
Blacksad's answer covers defining vars so I would just like to add the other scopes in which you may wish to have a value that is incremented from another value:
within a function's local scope:
user> (defn my-function [x]
(let [y (inc x)
z (+ x y)]
[x y z]))
#'user/my-function
user> (my-function 4)
[4 5 9]
and If you want to build a value incrementally to make the process more clear:
user> (defn my-function [x]
(let [y (inc x)
z (+ x y)
z (+ z 4)
z (* z z)]
[x y z]))
#'user/my-function
user> (my-function 4)
[4 5 169]
This can make the process more presentable, though it is not a "way to get variables back" and is really only useful in limited contexts. This pattern is used in clojure.core's threading macros.

Clojure: How can I bind a variable?

I have the following defined in clojure:
(def ax '(fn x [] (+ 1 z)))
(let [z 4]
(str (eval ax))
)
:but instead of returning :
5
: I get :
Unable to resolve symbol: z in this context
: I have tried changing "let" to "binding" but this still does not work. Does anyone know what is wrong here?
Making the smallest possible changes to your code to get it to work:
(def ^:dynamic z nil)
(def ax '(fn x [] (+ 1 z)))
(binding [z 4]
(str ((eval ax)))
)
The two changes are defining z as a dynamic var, so that the name resolves, and putting another paren around (eval ax), because ax is returning a function.
A little bit nicer is to change the definition of ax:
(def ^:dynamic z nil)
(def ax '(+ 1 z))
(binding [z 4]
(str (eval ax))
)
So evaluating ax immediately gets the result you want, rather than returning a function that does it.
Nicer again is to skip the eval:
(def ^:dynamic z nil)
(defn ax [] (+ 1 z))
(binding [z 5]
(str (ax))
)
But best of all is to not have z floating around as a var, and pass it in to ax as Mimsbrunnr and Joost suggested.
The short answer is don't use eval. You almost never need to, and certainly not here.
For example:
user> (defn ax [z]
(+ 1 z))
#'user/ax
user> (let [f #(ax 4)]
(f))
5
Right so I'm not entirely sure what you are trying to do here.
I mean this works, though it's not using eval it's defining x to be the function (fn [ x ] (+ x 1))
> (def x #(+ 1 %))
#'sandbox102711/x
> (x 4)
5
In the end, eval is not something you should be using. As a Lisp Cljoure's support for lambda abstraction and macros ( see the fn definition above ) should remove the need.