I defined a generic function taking 2 arguments:
(defgeneric interact (a b))
The order of the arguments should not be important, so (interact x y) and (interact y x) should be the same, but I don't want to define two methods that do the same for every combination of different objects.
A Method-Combination of this type should help:
(defmethod interact :around (a b)
(if (some-function a b)
;;some-function has to be true if (eq (class-of a) (class-of b))
;;else (some-function a b) is (not (some-function b a))
;;similar #'<=
(call-next method)
(interact b a))
But I would have to know #'some-function and be able to know the type of the arguments I have to define.
Edit: both proposed approaches have a few limitations discussed in the comments below. Please read them before using this answer!
Can I suggest two options - a working but hacky option for when you only have two arguments, and a vaguely sketched out generic approach which I think should work but I haven't written:
Option 1:
(defparameter *in-interact-generic-call* nil)
(defgeneric interact (x y))
(defmethod interact ((x T) (y T))
; this can be called on pretty much anything
(if *in-interact-generic-call*
(cause-some-kind-of-error) ; Replace this with a more sensible error call
(let ((*in-interact-generic-call* T))
(interact y x))))
(defmethod interact ((x integer) (y string))
; example
(print x )(prin1 y))
(interact 5 "hello") ; should print 5 "hello"
(interact "hello" 5) ; should print 5 "hello"
;(interact "hello" "hello") ; should cause an error
Essentially the idea is to define a generic function which always matches anything, use it to try to swap the arguments (to see if that matches anything better) and if it's already swapped the arguments then to raise some kind of error (I've not really done that right here).
Option 2
Define the generic function as something like interact-impl. Actually call the standard function (defined by defun) interact.
In interact, define a loop over all permutations of the order of your arguments. For each permutation try calling interact-impl (e.g. using (apply #'interact-impl current-permutation).)
At least in sbcl, no matching arguments gives me a simple-error. You probably would want to do a more detailed check that it's actually the right error. Thus the code in interact looks something like
; completely untested!
(do (all-permutations all-permutations (cdr all-permutations))
(...) ; some code to detect when all permutations are exhausted and raise an error
(let (current-permutation (first all-permutations))
(handler-case
(return (apply #'interact-impl current-permutation))
(simple-error () nil)) ; ignore and try the next option
)
)
So what you are looking for is an arbitrary linear order on the class objects.
How about string order on class names?
(defun class-less-p (a b)
"Lexicographic order on printable representation of class names."
(let* ((class-a (class-of a))
(name-a (symbol-name class-a))
(pack-a (package-name (symbol-package name-a)))
(class-b (class-of b))
(name-b (symbol-name class-b))
(pack-b (package-name (symbol-package name-b))))
(or (string< pack-a pack-b)
(and (string= pack-a pack-b)
(string<= name-a name-b)))))
I want to declare a list of lists, like so:
%% example 1
Xs = [
[[A],[[A]]],
[[A],[[A],[A]]],
[[A],[[A],[A],[A]]]
].
Here, the symbol A refers to the same variable in each list. Executing maplist(writeln,xs) results in the following output:
[[_G1],[[_G1]]]
[[_G1],[[_G1],[_G1]]]
[[_G1],[[_G1],[_G1],[_G1]]]
I want to use the same symbol A in each list, but for the variable to be distinct for each list, to give the following output:
[[_G1],[[_G1]]]
[[_G2],[[_G2],[_G2]]]
[[_G3],[[_G3],[_G3],[_G3]]]
The only way I make this work is give each list its own unique variable, like so:
%% example 2
Xs = [
[[A1],[[A1]]],
[[A2],[[A2],[A2]]],
[[A3],[[A3],[A3],[A3]]]
].
Is there any Prolog syntax, so that there is no need to number each variable, as per example 2? I tried adding brackets around the lists like so:
Xs = [
([[A],[[A]]]),
([[A],[[A],[A]]]),
([[A],[[A],[A],[A]]])
].
But this gives me the same output as example 1.
Variable names in Prolog have a scope that spans a single clause in a predicate definition, or a query at the top-level. So, this:
?- List = [A, A, A].
means a list with three times the same variable, A. If you put it into a predicate, it would be, say in a file my_lists.pl (I have not nested the lists like you, just to keep it simple):
my_list([A, A]).
my_list([A, A, A]).
my_list([A, A, A, A]).
The As in the three clauses are now not in the same lexical scope, so if you consult this predicate and then collect all possible instantiations of my_list(L) using for example findall/3, you get what you are after:
?- [my_lists].
true.
?- findall(L, my_list(L), Ls).
Ls = [[_G1945, _G1945],
[_G1933, _G1933, _G1933],
[_G1918, _G1918, _G1918, _G1918]].
Is this close to what you are looking for? What is it that you are trying to achieve?
If you want to write out variables and specify a precise name for them, you need the write-option variable_names/1. This answer explains how. Alternatively, you might use the legacy predicate numbervars/3 which unifies distinct variables with a term '$VAR'(N), and then use either writeq/1 or the write-option numbervars(true).
But both methods will not work in the case you indicate. In fact, it was sheer luck that your query
?- Xs = [[[A],[A]],[[A],[A],[A]],[[A],[A],[A],[A]]], maplist(writeln,Xs).
produced the same variables for the different lists. It's even worse, the very same goal writing the very same list, may produce different variable names for different invocations:
p(N) :-
length(_,N),
length(K,1),
writeq(K),
garbage_collect,
writeq(K).
For p(100), SICStus writes [_776][_46], SWI writes [_G517][_G3]. Brief, you caught Prolog on a good day. This is not surprising, for the standard only requires an "implementation dependent" value for a name with a few restrictions: It starts with underscore, and the remaining characters are different for different variables, and the same for the same variable within the same write goal. Here is ISO/IEC 13211-1:1995 on this:
7.10.5 Writing a term
When a term Term is output using write_term/3 (8.14.2)
the action which is taken is defined by the rules below:
a) If Term is a variable, a character sequence repre-
senting that variable is output. The sequence begins
with _ (underscore) and the remaining characters are
implementation dependent. The same character sequence
is used for each occurrence of a particular variable in
Term. A different character sequence is used for each
distinct variable in Term.
The reason for this is that a globally consistent naming of variables would produce a lot of overhead in implementations.
To summarize: If you want to use different variable names for the same variable, then use variable_names/1 with different arguments. If you want the variable to be actually different, then name them differently, or use copy_term/2 accordingly.
You can do it like this:
First, create the desired list structure, with different variables:
?- maplist(length, Lists, [2,3,4]).
Lists = [[X1, X2], [X3, X4, X5], [X6, X7, X8, X9]].
Then, using the following additional definition:
same_element(Ls) :- maplist(=([_]), Ls).
you can unify variables that are in the same sublist to the same term:
?- maplist(same_element, [[X1, X2], [X3, X4, X5], [X6, X7, X8, X9]]).
X1 = X2, X2 = [_G1141],
X3 = X4, X4 = X5, X5 = [_G1149],
X6 = X7, X7 = X8, X8 = X9, X9 = [_G1157].
In combination:
?- maplist(length, Lists, [2,3,4]),
maplist(same_element, Lists),
maplist(writeln, Lists).
yielding:
[[_G1079],[_G1079]]
[[_G1087],[_G1087],[_G1087]]
[[_G1095],[_G1095],[_G1095],[_G1095]]
Now, with the following Emacs definitions:
(defun nice-variables (start end)
(interactive "r")
(goto-char start)
(let ((n 1)
(variables nil)
(m (make-marker)))
(set-marker m end)
(while (and (<= (point) (marker-position m))
(re-search-forward "_G" (marker-position m) t))
(let* ((from (point))
(len (skip-chars-forward "0-9"))
(str (buffer-substring-no-properties from (+ from len)))
(num (assoc str variables)))
(delete-backward-char (+ len 2))
(if num
(insert (format "X%d" (cdr num)))
(setq variables (cons (cons str n) variables))
(insert (format "X%d" n))
(setq n (1+ n)))))))
and M-x nice-variables RET on the region, you get:
[[X1],[X1]]
[[X2],[X2],[X2]]
[[X3],[X3],[X3],[X3]]
This is also what I used on the output of the first query above, to make it more readable.
Thus, you can either generate the structure you want dynamically, by unifying variables you want to be the same, or copy & paste the output above and use it with slight modifications in your program directly.
How can I define mutator elisp functions? that is, how can I send parameters to an elisp function that can be modified inside the function for use outside the function (similar to non const reference variables or pointers in C++)? For example, suppose I had a function foo defined like
(defun foo (a b c d)
;do some stuff to b, c, and d
.
.
.
)
I might like to call it, say, as follows
(defun bar (x)
(let ((a) (b) (c) (y))
.
.
.
;a, b and c are nil at this point
(foo x a b c)
(setq y (some-other-function-of a b c x and-other-variables))
.
.
.
)) ... )
y)
I know that I could throw all my parameters local to some function into one big old list, evaluate the list at the end of the function and then go fetch these variables from some other list set to be the return value of that function (a list of stuff), i.e.
(setq return-list (foo read-only-x read-only-y))
(setq v_1 (car return-list))
(setq v_2 (cadr return-list))
.
.
but are there any better ways? All I have accomplished so far in my attempts to solve this is exiting the function with variables no different to how they were passed in
As for why I want to be able to do this I am simply trying refactor some large function F in such way that all collections of expressions related to some nameable concepts c live in their own little modules c_1, c_2, c_3, ... c_n that I can call from within F with whatever arguments I need to be updated along the way. That is to say, I would like F to look something like:
(defun F ( ... )
(let ((a_1) (a_2) ... )
(c_1 a_1 ... a_m)
(c_2 a_h ... a_i)
.
.
.
(c_n a_j ... a_k)
.
.
.
))...))
Two ways I can think of:
make the "function" foo a macro and not a function (if possible)
pass a newly created cons (or more of them) into the function, and replace the car and cdr of them via setcar/setcdr
In case the function is too complex, you can also combine both approaches - have a macro foo that creates a cons of a and b and calls a function foo0 with that cons, and later unpacks the car and cdr again.
In case you need more than 2 args, just use more than one cons as a paramter.
Just to show you how it can be done, but please don't do it, it's bad style.
(defun set-to (in-x out-y)
(set out-y in-x))
(let (x)
(set-to 10 'x)
x)
There's a case when this won't work though:
(let (in-x)
(set-to 10 'in-x)
in-x)
It's a bit like this C++ code
void set_to(int x, int* y) {
*y = x;
}
int y;
set_to(10, &y);
Actually I wish there were no non-const references in C++, so that
each mutator would have to be called with a pointer like above.
Again, don't do it unless it's really necessary.
Use instead multiple-value-bind or cl-flet.
This is part of a homework assignment so my goal is to understand why this is wrong. As I mentioned before I'm using Moscow ML.
fun filter pred = let
fun f ([], a) = []
| f ([], a) = a
| f (e::L, a) = if pred e then (f L (e::a) ) else (f L a)
in
f
end
The error I get is:
| f (e::L, a) = if pred e then (f L (e::a) ) else (f L a)
^
Type clash: expression of type
'a list cannot have type
'a list * 'b list
I have been reading up on documentation, and it really hasn't helped. What I really don't get is where 'b list is coming from. In our assignment we have to use an accumulator with tail recursion. I believe where my error is is how filter calls the function f. Filter takes the predicate as an argument and f should take the list and accumulator which is initially the empty list.
I've tried calling f like: f L [], But in other examples we didn't actually have to call f with its argument and it was somehow passed automatically.
Anyway, any help understanding where my mistake is and guidance on how to fix the problem would be greatly appreciated.
-aitee
(also if anyone could give me any tips on decoding the type expression errors that could also be very beneficial.)
(f L (e::a)) would work only if f were a curried function, of type 'a list -> 'a list -> 'a list. You should be doing:
if pred e then (f (L, (e::a))) else (f (L,a))
Btw., SMLNJ complains of a redundant match (two f ([], a) clauses are given).
You're confusing tupled versus curried function calls. Your definition of f demands a tuple, (a,b), but you're passing it arguments as f a b. Try replacing your recursive calls to f L ... with f (L,...) instead.
The type error is a little unhelpful, but it's basically saying that you're passing a list when it expects a 2-tuple of lists.
More out of curiousity that anything else (but with the expectation that it might occasionally be a useful trick for performance tuning), is it possible to use Clojure macros to "inline" an existing function?
i.e. I would like to be able to do something like:
(defn my-function [a b] (+ a b))
(defn add-3-numbers [a b c]
(inline (my-function
a
(inline (my-function
b
c)))))
And have it produce (at compile time) exactly the same function as if I had inlined the additions myself, such as:
(defn add-3-numbers [a b c]
(+ a (+ b c)))
In case you didn't know, you can define inlined functions using definline
(doc definline)
-------------------------
clojure.core/definline
([name & decl])
Macro
Experimental - like defmacro, except defines a named function whose
body is the expansion, calls to which may be expanded inline as if
it were a macro. Cannot be used with variadic (&) args.
nil
Also checking the source,
(source definline)
-------------------------
(defmacro definline
[name & decl]
(let [[pre-args [args expr]] (split-with (comp not vector?) decl)]
`(do
(defn ~name ~#pre-args ~args ~(apply (eval (list `fn args expr)) args))
(alter-meta! (var ~name) assoc :inline (fn ~name ~args ~expr))
(var ~name))))
definline simply defines a var with meta-data {:inline (fn definition)}. So although its not exactly what you were asking but you can rebind the var with new metadata to get inlined behavior.