Clojure: separating comp and partial arguments - clojure

Say I have a function that needs two arguments and where the order of arguments affects the results.
Is it possible to pass the first argument into a partial or comp function and the other aside of it, like this:
(defn bar [arg1 arg2] (- arg1 arg2))
(def baz (partial (bar arg1)))
(def qux (comp str (bar arg1)))
(baz arg2)
(qux arg2)
If I want to pass arg2 into the function, could I do something like this?
(def baz2 (partial (bar _ arg2)))
(def qux2 (comp str (bar _ arg2)))
(baz arg1)
(qux arg1)

partial only "fills in" arguments on the left side, so if you need to skip arguments you must use fn:
(def baz2 #(bar %1 arg2))
Note also that comp requires that all its arguments be functions, so your qux and qux2 are actually nonsense. They should be:
(def qux (comp str baz))
(def qux2 (comp str baz2))
In general, Clojure core functions will place the variable most likely to change last to make composition with comp and partial more natural. (E.g., the collection argument is almost always last in Clojure, except for things like into where it makes sense to put it first.) When you design your own functions you should stick to this convention so you can compose your functions more easily.

Scheme SRFI 26 has a useful macro cut for slotting parameters like this.
Usage would be like so for your subtracting bar:
((cut bar <> 1) 2)
;=> 1
((comp str (cut - <> 1)) 2)
;=> "1"
Where the <> symbol represents the slot to be filled.
It is a fun exercise to implement a cut in Clojure yourself, but here is one port by #Baishampayan Ghose.

Here's what I got in a repl:
user=> (defn bar [arg1 arg2] (- arg1 arg2))
#'user/bar
user=> (def baz (partial bar 5))
#'user/baz
user=> (def qux (comp str baz))
#'user/qux
user=> (baz 2)
3
user=> (qux 2)
"3"
It's the closest I could get from your first example.
For the second example, maybe a simple defn is better than a partial def:
user=> (defn baz2 [x] (bar x 5))
#'user/baz2
user=> (def qux2 (comp str baz2))
#'user/qux2
user=> (baz2 2)
-3
user=> (qux2 2)
"-3"
I'd suggest you start a repl and try it yourself, it's the second best way to discover a language that I know of (TDD being the first).
Cheers!

Related

How to combine explicit args with variable args in function call

In JavaScript, one can do the following:
function foo(arg1, arg2, arg3) {
...
}
var others = [ 'two', 'three' ];
foo('one', ...others); // same as foo('one', 'two', 'three')
In Clojure, "variable args" can be accepted like so:
(defn foo [arg1 & others]
...)
But to pass them in combination with other args, you have to do this:
(apply foo (concat '("one") others))
Which is frankly really ugly. It's also impossible when what you need to do is recur:
(apply recur (concat '("one") others)) ;; doesn't work
Is there a better way to do this? And if not, is there any way at all to accomplish it in the recur case?
But to pass them in combination with other args, you have to do this:
(apply foo (concat '("one") others))
You don't have to do that: apply is also a variadic function that can take arguments before the final sequence argument e.g.
(apply foo "one" others)
You can pass any number of individual arguments before the final sequence argument to apply.
user=> (defn foo [arg1 & args] (apply println arg1 args))
#'user/foo
user=> (apply foo "one" 2 "three" [4 "five" 6.0])
one 2 three 4 five 6.0
To further demonstrate, these calls to + are functionally equivalent:
(apply + 1 2 [3])
(apply + 1 [2 3])
(apply + [1 2 3])
It's also impossible when what you need to do is recur
recur is a special form, and apply doesn't work with it like it would a typical Clojure function.
is there any way at all to accomplish it in the recur case?
Not with apply. You can recur with variadic args, but you can't (apply recur ...).

Unexpected behavior when using recur in a variadic function

I was writing an answer for this challenge, when I needed to give a recursive function an optional parameter. I ended up with something kind of equivalent to:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
My intent was for b? to act as an optional parameter. If it wasn't supplied, it would be defaulted to nil via destructuring.
Instead of running though, it gave me an error:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
After some debugging, I realized that for some reason the rest parameter wasn't a list as I'd expect, but just the passed number! The error was coming about because it tried to destructure the number.
I can fix it by getting rid of the wrapper list in the parameter list:
(defn func [a & b]
...
But this just looks wrong. I know the rest parameter should be a list, but b is actually just a number. If I use "unoptimized" recursion, it works as I'd expect:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
Can anyone explain what's going on here?
This appears to be a known difference
; Note that recur can be surprising when using variadic functions.
(defn foo [& args]
(let [[x & more] args]
(prn x)
(if more (recur more) nil)))
(defn bar [& args]
(let [[x & more] args]
(prn x)
(if more (bar more) nil)))
; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...
user=> (foo :a :b :c)
:a
:b
:c
nil
user=> (bar :a :b :c)
:a
(:b :c)
nil
; The difference arises because recur does not gather variadic/rest args
; into a seq.
It's the last comment that describes the difference.

Mapping a symbol-binding macro (in a fn) in Clojure

I define a macro to bind a symbol derived from a string to the string like this:
lein repl
... Clojure 1.8.0 ...
user=> (defmacro foo [s] `(def ~(symbol s) ~s))
#'user/foo
It works as expected when invoked at top level:
user=> (foo "asdf")
#'user/asdf
user=> asdf
"asdf"
But when I try to map a function that invokes the macro over a sequence, the macro binds the function parameter symbol rather than the one I want:
user=> (map (fn [x] (foo x)) ["qwer"])
(#'user/x)
user=> x
"qwer"
user=> qwer
CompilerException ... Unable to resolve symbol: qwer ...
The following alternative binds the temporary symbol created by Clojure:
user=> (map #(foo %) ["qwer"])
(#'user/p1__1253#)
It also doesn't work when wrapped in doall as suggested by some of the existing answers I researched on StackOverflow.
How can I define a symbol-binding macro that I can map (in a function or otherwise) over a collection of strings?
map is a function and foo is a macro. Since macro expansion happens at compile time and functions are executed at run time, defining a symbol-binding macro that you can map (and thus expand at run time) is impossible.
What you can do is something like this:
(defn foo2 [s]
`(def ~(symbol s) ~s))
(defmacro foos [ss]
`(do ~#(map foo2 ss)))
(foos ["asdf" "qwer"])
asdf ;; => "asdf"
qwer ;; => "qwer"
Now it's the other way around: the macro is expanded using the functions map and foo.
Here is a way of doing it. The solution first shows how the macro foo works, then uses an intermediate solution with a function map-foo-fn and then eval.
The final solution uses a second macro map-foo-mcr. This seems to be needed since (def ...) is a special form. This is similar (but not identical) to the problem of "turtles all the way down" where using a macro in one place requires all callers to also be macros, not functions.
(ns clj.core
(:require
[tupelo.core :as t] ))
(t/refer-tupelo)
(defmacro foo
[arg]
`(def ~(symbol arg) ~arg))
(foo "aa")
(spyx aa)
(defn map-foo-fn
[coll]
(cons 'do
(forv [elem coll]
(list 'foo elem))))
(newline)
(prn (map-foo-fn ["bb"] ))
(eval (map-foo-fn ["bb"] ))
(spyx bb)
(defmacro map-foo-mcr
[coll]
`(do
~#(forv [elem coll]
(list 'foo elem))))
(newline)
(println (macroexpand-1 '(map-foo-mcr ["cc" "dd"] )))
(map-foo-mcr ["cc" "dd"] )
(spyx cc)
(spyx dd)
Results:
aa => "aa"
(do (foo "bb"))
bb => "bb"
(do (foo cc) (foo dd))
cc => "cc"
dd => "dd"
Remember that, while macros can do one thing that functions can't (avoid arg evaluation), macros cannot do other things that functions can. In particular, macros can't be passed to map et al where higher-order-function argument is required.
For more details see http://www.braveclojure.com/writing-macros and search for "Macros All the Way Down"
Note that project.clj needs
:dependencies [
[tupelo "0.9.13"]
for spyx to work

Is there a way to create a named function in clojure which is only visible in function scope?

In Scheme I can do something like this:
(define (adder)
(define (one) 1)
(define (two) 2)
(+ (one) (two)))
Calling adder results in 3 while calling one will yield an error since one is only visible within the scope of adder.
In Clojure if I do something similar
(defn adder []
(defn one [] 1)
(defn two [] 2)
(+ (one) (two)))
one and two will pollute my namespace since defn uses def internally which creates bindings in the current namespace.
Is there a function/macro which creates named functions in local scope?
The reason for my question is that I got used to the way Scheme works. Naming my local functions that way often makes my code more readable.
Try letfn:
Takes a vector of function specs and a body, and generates a set of
bindings of functions to their names. All of the names are available
in all of the definitions of the functions, as well as the body.
(defn adder []
(letfn [(one [] 1)
(two [] 2)]
(+ (one) (two))))
Additionally to Alex's excellent answer, any fn can be named.
(defn adder []
(let [one (fn [] 1)
two (fn [] (+ (one) (one)))]
(+ (one) (two))))
This is useful if you already have a let block.
If an fn refers to itself, it needs a name of its own
(defn silly []
(let [constant 5
thing (fn thong
([a] (+ a constant))
([] (inc (thong constant))))]
(* (thing) (thing))))
The name the fn is bound to need not be the same as the name it knows itself by.
If you want a function that is visible to the current namespace but not visible by other namespaces - you can use defn-
defn-
macro
Usage: (defn- name & decls)
same as defn, yielding non-public def
from http://clojuredocs.org/clojure_core/clojure.core/defn-
user=> (ns test)
nil
test=> (defn- foo [] "World!")
#'test/foo
test=> (defn bar [] (str "Hello " (foo)))
#'test/bar
test=> (foo)
"World!"
test=> (bar)
"Hello World!"
test=> (ns playground)
nil
playground=> (test/bar)
"Hello World!"
;; Error will be thrown
;; var: #'test/foo is not public
playground=> (test/foo)

Clojure Keyword and Optional Argument Problem

I want to create a function that takes in a required argument x, and either a optional argument opt1 OR a keyword argument opt2.
Right now I have
(defn foo x & [opt1 {:keys [opt2]}]
...
But the above signature only lets me pass in keyword argument opt2 when both x and opt1 is present like
(foo 'x 'opt1 {:opt2 'opt2})
not like this
(foo 'x {:opt2 'opt2})
Please help me create a function that takes a required argument X and either opt1 or opt2, where opt2 is a keyword argument.
Thank you.
EDIT: I want to do the same for other macros as well. So I still need to use the defmacro.
The problem is ambiguity. Consider a function (fn foo [x y & args]) that takes two optional arguments and then any number of keyword arguments. If you then call it like (foo :bar :baz), how does your program handle it? x => :bar, y => :baz? Or x and y not provided, with a single :bar => :baz keyword argument?
Even in Common Lisp, which has arguably even more flexibility than Clojure in parsing function parameters, mixing optional and keyword arguments is not recommended, according to at least one popular book.
Your best bet is to change all of your arguments to positional arguments, or all of your parameters to keyword arguments. If you use keyword arguments, you can use hash-map destructuring to provide defaults for "optional" keyword parameters.
user> (defn foo [& {:keys [x y bar]
:or {x 1 y 2 bar 3}}]
(prn [x y bar]))
#'user/foo
user> (foo)
[1 2 3]
nil
user> (foo :bar :baz)
[1 2 :baz]
nil
you have to check if the aditional arguments are keyword arguments or not anyway (I assume your or is an exclusive or) so you can do it like this:
(defn foo [& args]
(if (= (count args) 1)
(let [[opt1] args] (println opt1))
(let [{:keys [opt2]} args] (println opt2))))
check the arguments if they are keyword arguments or not. As you only have one optional parameter it's easy: check if there's only one as keyword arguments require two.