I have this function definition, but I was wondering if it was possible to do this with just a def and higher order functions (i'd like the result to take args in the same order)
(defn f1
[a b c]
(f2
(partial f3 a)
b c))
f2 and f3 look like (keeping arguments relevantly named):
(defn f2
[f b c]
(my-fn-using f b c))
(defn f3
[a x c]
(another-fn-using a x c))
I'm not a 100% sure I understand what you are asking, but here's my take on an answer.
Converting f1 to a HOF could involve modifying it to take the arguments [f g a b c] and calling it using f and g as my-fn-using and another-fn-using.
(defn f1 [f g a b c]
(f (partial g a) b c))
You would then call it as:
(f1 my-fn-using another-fn-using a b c)
Which would be applied as:
(my-fn-using (partial another-fn-using a) b c)
The reason that I'm not sure if this is what you are looking for is that you mention "nested function arguments", but I don't see where those are. Missing arguments for another-fn-using come from inside my-fn-using when the former is called, and the latter gets its arguments directly.
For example:
(defn my-fn-using [f b c]
(let [x [:b b]]
;; do stuff using b and/or c
(f x c)))
(defn another-fn-using [a x c]
;; do other stuff using a x c
[a x c])
;; call f1
(f1 my-fn-using another-fn-using 1 2 3)
;; or create a partially applied function that takes [a b c]
(def f (partial f1 my-fn-using another-fn-using))
(f 1 2 3)
Related
Given:
(defn some-fn
[]
(let [a 1
b 2
c (+ a b)]
(println c)))
and given that there are multiple such functions, where:
a and b have different values;
c is always equal to (+ a b)
is there a way to extract c without making it a function, which accepts a and b as arguments. So, I don't want:
(defn c-outside
[a b]
(+ a b))
(defn some-fn
[]
(let [a 1
b 2
c (c-outside a b)]
(println c)))
but ideally, something like:
(defn c-outside
[]
(+ a b))
(defn some-fn
[]
(let [a 1
b 2
c (c-outside)]
(println c)))
Is there a way to make c-outside look for the values of a and b in the context, in which it is called? Do I need a macro for that?
there is a way to do it using dynamic bindings:
user> (def ^:dynamic a 10)
#'user/a
user> (def ^:dynamic b 20)
#'user/b
user> (defn c-outside []
(+ a b))
user> (defn some-fn []
(binding [a 1
b 2]
(c-outside)))
#'user/some-fn
user> (some-fn)
;;=> 3
user> (c-outside)
;;=> 30
the trick is that you can temporarily rebind some dynamic vars for the 'duration' of some scope.
This is mostly used in clojure for concurrent programming: the dynamically bound vars keep their values in the threads, spawned from inside the block (as far as i remember)
Otherwise, i see more potential harm from this feature, than the profit, since it obscures the code, adding some unneeded implicit behaviour.
Also as far as i know, this is one of the most arguable features in lisps (in common lisp, to be more specific)
Almost in any case it is better to pass a and b values explicitly to the summing function, since it makes in clean and therefore testable, and helps to reason about it's correctness and performance, and increases readability
you could also think of using macro for that, like this for example:
user> (defmacro c-outside-1 []
`(+ ~'x ~'y))
#'user/c-outside-1
user> (defn some-fn-1 []
(let [x 1
y 2]
(c-outside-1)))
#'user/some-fn-1
user> (some-fn-1)
;;=> 3
but that idea is obviously even worse.
I can seem to wrap my head around macros in Clojure. I'm probably missing something basic. First, allow me to describe an example of what I want.
(defmacro macrotest [v] `(d ...))
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (d (b c))
In other words, the var passed to macrotest is resolved, but not evaluated further.
Providing the macro with the value of the var works:
(defmacro macrotest [v] `(d ~v))
(macroexpand-1 '(macrotest (b c)))
; => (d (b c))
But providing the var does not:
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (d a)
Is it possible to resolve a var in Clojure macro, but not evaluate its value?
EDIT: What I want seems to be possible with eval:
(defmacro macrotest [v] `(d ~(eval v)))
(def a '(b c))
(macroexpand-1 '(macrotest a))
; => (user/d (b c))
Its important to understand that macros evaluate at compile time, not at runtime.
at compile time var a does not yet have a value, so its value is not passed to the macro, only its name. However, when you explicitly pass the "value" - well, then it exists at compile time, and you see that it "works".
Lexical environment
Using eval inside a macro is bad practice. Sure, the following works:
(macroexpand-1 '(macrotest a))
; => (user/d (b c))
... but then, this does not work as expected:
(macroexpand-1 '(let [a "oh no"]
(macrotest a)))
; => (user/d (b c))
Surely you would like the macro to evaluate a as it was defined locally, not using the global variable bound to it, but you cannot because the macro does not evaluate v in the right lexical context. And this is the key to understanding macros: they take code and produce code; any data manipulated by that code is not available to you yet. In other words, the moment at which macros are expanded might be totally unrelated to the time their resulting code is evaluated: anything you evaluate while a macro is being executed is probably evaluated too soon w.r.t. the relevance of your data.
What do you want to do?
There is a form named macrotest which should accepts an argument, v and then perform as-if you had form d applied to it. But:
(macrotest (b c)) should not evaluate (b c), just copy it untouched to produce (d (b c)).
(macrotest a) should evaluate a, which results in a quoted form, and place that form in the resulting code, also returning (d (b c)).
You have a problem here, because the meaning changes radically in one or the other case. Either you evaluate an argument, in which case you must quote (b c) and you write:
(defmacro macrotest [v] `(d ~v))
... which requires that d is ready to handle quoted arguments; or you are okay with the argument being not evaluated.
With the same d as above, you can quote the argument explicitly:
(defmacro macrotest [v] `(d '~v))
However, if d itself is a macro that does not evaluate its argument, you have to avoid the quote in front of ~v.
I'm currently writing functions with undefined number of arities and I so looked for examples in clojure.core and so on.
This is for example the definition of comp (clojure.core)
(defn comp
"Takes a set of functions and returns a fn that is the composition
of those fns. The returned fn takes a variable number of args,
applies the rightmost of fns to the args, the next
fn (right-to-left) to the result, etc."
{:added "1.0"
:static true}
([] identity)
([f] f)
([f g]
(fn
([] (f (g)))
([x] (f (g x)))
([x y] (f (g x y)))
([x y z] (f (g x y z)))
([x y z & args] (f (apply g x y z args)))))
([f g & fs]
(reduce1 comp (list* f g fs))))
As you can see, for the arities [f g], the code detail the values for 2 and 3 arguments (x y ; x, y, z) even if it could just have directly jumped to [x & args].
Is there any performance reason ? Or is it a convention ?
I suppose that calling apply could impact performance, I don't know.
We generally use at most 3D functions and composition of 2 functions in real lif, maybe it's because of that.
Thanks
Clojure's core library is implemented often in ways that are not particularly idiomatic, specifically for performance reasons. If you are writing a function that is going to be fundamental to most of the lines of code in your program, you could do the same, but in general this is not elegant or particularly advised.
'() is a syntax sugar for (quote ()). But what does '[] mean? Quote a vector?
For example:
(use '[clojure.test :as t])
(.get '[a b c] 1)
(.containsAll '[a b c] '[b c])
((fnth 5) '[a b c d e])
Precisely. ' is a synonym for quote, so
'[a b c]
is just
(quote [a b c])
quote prevents evaluation of a Clojure code, so quoting the whole vector is essentially the same as quoting every single element of it:
['a 'b 'c]
It allows you to produce a vector of symbols, without explicitly calling symbol function:
[(symbol "a") (symbol "b") (symbol "c")]
Clojure is awesome, we all know this, but that's not the point. I'm wondering what the idiomatic way of creating and managing higher-order functions in a Haskell-like way is. In Clojure I can do the following:
(defn sum [a b] (+ a b))
But (sum 1) doesn't return a function: it causes an error. Of course, you can do something like this:
(defn sum
([a] (partial + a))
([a b] (+ a b)))
In this case:
user=> (sum 1)
#<core$partial$fn__3678 clojure.core$partial$fn__3678#1acaf0ed>
user=> ((sum 1) 2)
3
But it doesn't seem like the right way to proceed. Any ideas?
I'm not talking about implementing the sum function, I'm talking at a higher level of abstraction. Are there any idiomatic patterns to follow? Some macro? Is the best way defining a macro or are there alternative solutions?
Someone has already implememented this on the Clojure group. You can specify how many args a function has, and it will curry itself for you until it gets that many.
The reason this doesn't happen by default in Clojure is that we prefer variadic functions to auto-curried functions, I suppose.
I've played a bit with the functions suggested by amalloy. I don't like the explicit specification of the number of argument to curry on. So I've created my custom macro. This is the old way to specific an high order function:
(defn-decorated old-sum
[(curry* 3)]
[a b c]
(+ a b c))
This is my new macro:
(defmacro defn-ho
[fn-name & defn-stuff]
(let [number-of-args (count (first defn-stuff))]
`(defn-decorated ~fn-name [(curry* ~number-of-args)] ~#defn-stuff)))
And this is the new implicit way:
(defn-ho new-sum [a b c] (+ a b c))
As you can see there is no trace of (curry) and other stuff, just define your currified function as before.
Guys, what do you think? Ideas? Suggestions?
Bye!
Alfedo
Edit: I've modified the macro according the amalloy issue about docstring. This is the updated version:
(defmacro defhigh
"Like the original defn-decorated, but the number of argument to curry on
is implicit."
[fn-name & defn-stuff]
(let [[fst snd] (take 2 defn-stuff)
num-of-args (if (string? fst) (count snd) (count fst))]
`(defn-decorated ~fn-name [(curry* ~num-of-args)] ~#defn-stuff)))
I don't like the if statement inside the second binding. Any ideas about making it more succint?
This will allow you to do what you want:
(defn curry
([f len] (curry f len []))
([f len applied]
(fn [& more]
(let [args (concat applied (if (= 0 (count more)) [nil] more))]
(if (< (count args) len)
(curry f len args)
(apply f args))))))
Here's how to use it:
(def add (curry + 2)) ; read: curry plus to 2 positions
((add 10) 1) ; => 11
The conditional with the [nil] is meant to ensure that every application ensures some forward progress to the curried state. There's a long explanation behind it but I have found it useful. If you don't like this bit, you could set args as:
[args (concat applied more)]
Unlike JavaScript we have no way of knowing the arity of the passed function and so you must specify the length you expect. This makes a lot of sense in Clojure[Script] where a function may have multiple arities.