All, I'm starting to take a look at the Clojure language, and had a couple questions about something I'm trying to do. The broad objective is to alias the sequence function every?
to all?
. I'm sure there's a function or macro that does alias-ing (or something along those lines) but I wanted to see if it was possible with some of the basic constructs I know thus far. My approach was going to be to define a function called all?
that applies its arguments to the every?
implementation.
I'm curious to see if this can be made agnostic, so I wanted to parameter my alias function to take two arguments, the new name (as a Keyword) and the old name (as a function reference). In striving towards this goal, I've encountered two problems.
1) Defining named functions with Keywords throws errors. Apparently it wants clojure.lang.IObj
.
user=> (defn :foo "bar")
java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to clojure.lang.IObj (NO_SOURCE_FILE:0)
Is there a function to cast a Keyword to an IObj, or other means to parameterize the name of a newly defined function with some provided value? (In Ruby, define_method amongst other techniques does this)
irb(main)> self.class.instance_eval do
irb(main)* define_method(:foo) { "bar" }
irb(main)> end
=> #<Proc>
irb(main)> foo
=> "bar"
2) Collect all arguments to a function into a single variable. Even basic functions such as (+ 1 2 3 4)
take a variable amount of arguments. All the function definition techniques I've seen so far take a specific amount of arguments, with no way to just aggregate everything in a list for handling in the function body. Once again, what I'm going for is done in Ruby like so:
irb(main)> def foo(*args)
irb(main)> p args
irb(main)> end
=> nil
irb(main)> foo(1, 2, 3)
[1, 2, 3]
=> nil
Thanks for any help you can provide me!
I'll answer in bullet points, since the questions can be split neatly into a number of separate issues.
Something which is implicitly contained in what is to follow, but which perhaps warrants a bullet of its own: the top-level objects created by def
& Co. (and in particular by defn
) are Vars. So what you actually want to do is to alias a Var; functions are just regular values which don't really have names (except they may have a name bound to themselves locally inside their bodies; that's nothing to do with the issue at hand, though).
There is indeed an "aliasing macro" available in Clojure -- clojure.contrib.def/defalias
:
(use '[clojure.contrib.def :only [defalias]])
(defalias foo bar)
; => foo can now be used in place of bar
The advantage of this over (def foo bar)
is that it copies over metadata (such as the docstring); it even appears to work with macros in the current HEAD, although I recall a bug which prevented that in earlier versions.
Vars are named by symbols, not keywords. Symbol literals in Clojure (and other Lisps) do not start with colons (:foo
is a keyword, not a symbol). Thus to define a function called foo
you should write
(defn foo [...] ...)
defn
is a helper macro easing the creation of new function-holding Vars by allowing the programmer to use a mix of def
& fn
syntax. So defn
is out of question for creating Vars with preexisting values (which might be functions), as is required for creating aliases; use defalias
or simply def
instead.
To create a variadic function, use the following syntax:
(fn [x y & args] ...)
x
and y
will be required positional arguments; the rest of the arguments passed to the function (any number of them) will be collected into a seq and available under the name args
. You don't have to specify any "required positional arguments" if they are not needed: (fn [& args] ...)
.
To create a Var holding a variadic function, use
(defn foo [x y & args] ...)
To apply a function to some arguments you've got assembled into a seqable object (such as the args
seq in the above examples or perhaps a vector &c.), use apply
:
(defn all? [& args]
(apply every? args))
If you want to write a function to create aliases -- as opposed to a macro -- you'll need to investigate the functions intern
, with-meta
, meta
-- and possibly resolve
/ ns-resolve
, depending on whether the function is to accept symbols or Vars. I'll leave filling in the details as an exercise to the reader. :-)
All you need to do is bind the every? function to the all? symbol, which is done via def:
(def all? every?)
For a bit more on this, see Clojure macro to create a synonym for a function
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With