append/3 is a very powerful predicate. Suppose I want a predicate that works the same way but for SWI-Prolog's strings.
The easiest approach I see is to transform those strings into lists with string_codes/2, then apply append/3, then use string_codes/2 back. The big problem with this approach is that string_codes/2 does not work if both variables are not unified.
Here is an extremely ugly solution I came up with, which checks which strings are unified to apply string_codes/2 when needed:
append_strings(S1, S2, S3) :-
nonvar(S1),
nonvar(S2),!,
string_codes(S1, A),
string_codes(S2, B),
append(A,B,C),
string_codes(S3, C).
append_strings(S1, S2, S3) :-
nonvar(S1),
nonvar(S3),!,
string_codes(S1, A),
string_codes(S3, C),
append(A,B,C),
string_codes(S2, B).
append_strings(S1, S2, S3) :-
nonvar(S2),
nonvar(S3),!,
string_codes(S2, B),
string_codes(S3, C),
append(A,B,C),
string_codes(S1, A).
append_strings(S1, S2, S3) :-
nonvar(S3),
string_codes(S3, C),
append(A,B,C),
string_codes(S1, A),
string_codes(S2, B).
This yields the correct results for the following cases:
?- append_strings("test","auie","testauie").
true.
?- append_strings("test",A,"testauie").
A = "auie".
?- append_strings(A,"auie","testauie").
A = "test" ;
false.
?- append_strings(A,B,"testauie").
A = "",
B = "testauie" ;
A = "t",
B = "estauie" ;
A = "te",
B = "stauie" ;
A = "tes",
B = "tauie" ;
A = "test",
B = "auie" ;
A = "testa",
B = "uie" ;
A = "testau",
B = "ie" ;
A = "testaui",
B = "e" ;
A = "testauie",
B = "" ;
false.
Is there really no way to make things simpler than this? Suppose I want to make a whole bunch of predicates that work with strings just like they would with lists: I obviously don't want to have to write what I did for append/3 for all of them. But I also don't want to work with code strings because then I have no way of knowing whether I am manipulating a normal list or really a string.
Since the predicate is working on lists, it seems tempting to me to use DCGs. First let's observe that strings in Prolog are really lists of character codes:
?- X="test".
X = [116,101,115,116]
Of course this is not very readable, so let's see the characters themselves intead of their codes:
?- set_prolog_flag(double_quotes,chars).
yes
?- X="test".
X = [t,e,s,t]
That's better. Thinking about the relation the predicate should describe, I opt for a descriptive name like list_list_appended/3. This predicate has one goal: a dcg-rule, let's call it list_list//2, that uses another dcg, let's call it list//2, to actually write the lists:
list_list_appended(L1,L2,L3) :-
phrase(list_list(L1,L2),L3). % L3 is L1+L2
list([]) --> % if the list is empty ...
[]. % ... there's nothing in the list
list([X|Xs]) --> % if there's a head element ...
[X], % ... it's in the list
list(Xs). % the tail is also a list
list_list(L1,L2) --> % the list consists of ...
list(L1), % ... L1 followed by ...
list(L2). % L2
Your example queries:
?- list_list_appended("test","auie","testauie").
yes
?- list_list_appended(L1,"auie","testauie").
L1 = [t,e,s,t] ? ;
no
?- list_list_appended("test",L2,"testauie").
L2 = [a,u,i,e] ? ;
no
?- list_list_appended("test","auie",L3).
L3 = [t,e,s,t,a,u,i,e]
?- list_list_appended(L1,L2,"testauie").
L1 = [],
L2 = [t,e,s,t,a,u,i,e] ? ;
L1 = [t],
L2 = [e,s,t,a,u,i,e] ? ;
L1 = [t,e],
L2 = [s,t,a,u,i,e] ? ;
L1 = [t,e,s],
L2 = [t,a,u,i,e] ? ;
L1 = [t,e,s,t],
L2 = [a,u,i,e] ? ;
L1 = [t,e,s,t,a],
L2 = [u,i,e] ? ;
L1 = [t,e,s,t,a,u],
L2 = [i,e] ? ;
L1 = [t,e,s,t,a,u,i],
L2 = [e] ? ;
L1 = [t,e,s,t,a,u,i,e],
L2 = [] ? ;
no
As a SWI user you could also use this library in combination with set_prolog_flag(double_quotes,chars). to get the output in desired form. Refer to this answer for details.
Just use string_concat/3. Like ISO atom_concat/3, it can be used in many modes, including (-,-,+).
This is a more compact definition:
append_strings(S1, S2, S3):-
append_strings1(S1, L1, [1]-[], N1),
append_strings1(S2, L2, [1|N1]-N1, N2),
append_strings1(S3, L3, [1,1|N2]-N2, N3),
(N3\=[_,_|_] ->instantiation_error(append_strings/3); true),
append(L1, L2, L3),
(ground(S1)->true;string_codes(S1, L1)),
(ground(S2)->true;string_codes(S2, L2)),
(ground(S3)->true;string_codes(S3, L3)).
append_strings1(S, L, G-NG, N):-
(ground(S) -> (string_codes(S, L), N=G) ; N=NG).
It checks whether each argument is ground and tries to convert to codes, then checks if either the third argument is ground or the other two are, and throws an instantiation error if conditions are not met.
After the append it converts back to string arguments which where not ground.
there has been a similar question some time ago, I will show my proposal, revised
:- meta_predicate when_(0).
when_(P) :-
strip_module(P,_,Q), Q =.. [_|As],
or_list(As, Exp), % hurry debugging :-) display(Exp),
when(Exp, P).
or_list([A], ground(A)) :- !.
or_list([A|As], (ground(A);Exp)) :- or_list(As, Exp).
append_strings(S1, S2, S3) :-
maplist(when_, [string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C)]).
If you are interested, I can add an operator to hide the syntax details, to get something like
append_strings(S1, S2, S3) -:-
string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C).
Being new with CL, I play a lot with simple algorithms. For instance, I tried to implement a function for removing all unique elements in a list.
(1 2 2 3 3 4 5 3) -> (2 2 3 3 3)
First attempt lead to this code:
(defun remove-unique (items)
(let ((duplicates (set-difference items (remove-duplicates items :test #'equal))))
(append duplicates (remove-duplicates duplicates :test #'equal))))
This works ok with strings but does always return NIL for numbers. Reading a bit more about set-difference I've learned that it isn't suppose to work with duplicate populated lists at all, it just works somehow in my case, so I abandoned the approach as unportable and moved along.
Another attempt is:
(defun remove-unique (items)
(loop for item in items
when (member item (cdr (member item items)))
collect item))
And this works ok with numbers, but returns NIL for strings.
Apparently there is a core difference between strings and numbers I don't understand. How come list processing functions such as member and set-difference work differently on them?
The equality comparison for numbers, characters and strings is indeed different. Equal, which you should be wary to use because it is more expensive, does structure equality (so it descends on some objects). eq does object equality. And eql does object equality for most cases except for numbers (where they check type and value) and characters (where they check 'value')
See the hyperspec entries for equal, eql and eq for more information.
Strings are more related to lists than numbers since both lists and strings are sequences.
"Hello" is a sequence (compund data type) starting with the primitive character value #\H and ending with #\o.
'(1 2 3) is a sequence (compond data type) starting with the primitive numeric value 1 and ending with 3.
Characters are similar to numbers in that they are primitive values. Primitive values can be compared using eql while sequences, that are not the same object, can be compared using equal
(setq list1 (list 1 2 3))
(setq list2 (list 1 2 3))
(eql list1 list2)
;==> NIL
(equal list1 list2)
;==> T
;; comparing first element of both lists using eql
(eql (car list1) (car list2))
;==> T
(setq string1 "Hello")
(setq string2 "Hello")
(eql string1 string2)
;==> NIL
(equal string1 string2)
;==> T
;; comparing first character of both strings using eql
(eql (elt string1 0) (elt string2 0))
;==> T
Most (if not all) functions in Common Lisp that compares something usually has an optional named argument :test where you can supply how elements compare. the default usually is eql. To make them behave corretly with sequences you need to supply #'equal as :test.
(defun remove-unique (items &key (test 'eql))
(loop
:with table := (make-hash-table :test test)
:for element :in items :do
(setf (gethash element table)
(1+ (gethash element table 0)))
:finally
(return
(loop
:for k :being :the :hash-keys :of table
:using (:hash-value v)
:when (> v 1) :nconc (make-list v :initial-element k)))))
(defun remove-unique (items &key (test 'eql))
(loop
:with table := (make-hash-table :test test)
:for element :in items :do
(setf (gethash element table)
(1+ (gethash element table 0)))
:finally
(return
(loop
:for element :in items
:unless (= 1 (gethash element table))
:collect element))))
I'd probably use the first variant because it makes less reads from hash-table, but you'd need to check that items in the list aren't modified later in place.
(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3") :test #'equal)
gives:
("2" "2" "3" "3" "3")
but
(remove-unique '("1" "2" "2" "3" "3" "4" "5" "3"))
gives:
NIL
I want to write some nice Math with DrRacket(R5RS but not only) (Racket Tag is a bit empty).
I would really like to code some matrix stuff like:
(3 3 3) (5 3 4)
(4 4 4) -> (5 3 4)
(5 5 5) (5 3 4)
And other stuff like this to set up some nice gimp filters...
Some folks pointed out, this could be done via lists inside lists, but I can't think of a practical example here...
I am looking forward to your reply.
Yours sincerely, Andreas_P
A few notes:
1) what do you mean with Scheme "is built in within the core"? GIMP now has a native Python-fu along with Script-fu
2) the Lisp that won Google AI Challenge is Common Lisp, not Scheme
3) I am not sure, but the Script-fu console states TinyScheme, thus I would expect it to be really essential, with little library support, with respect to more complete Scheme implementations
Anyway, I tried a few example on matrices "the Scheme way". For the sake of simplicity, they lack any control on the input data, but for simple examples they work fine on DrRacket.
(define (vect-sum x y)
(cond
((empty? x) empty)
(else
(cons (+ (first x) (first y)) (vect-sum (rest x) (rest y))))))
(define (scalar-prod a v)
(cond
((empty? v) empty)
(else
(cons (* a (first v)) (scalar-prod a (rest v))))))
(define (matr-sum x y)
(cond
((empty? x) empty)
(else
(cons (vect-sum (first x) (first y))
(matr-sum (rest x) (rest y))))))
(define (matr-scalar-prod a m)
(cond
((empty? m) empty)
(else
(cons (scalar-prod a (first m)) (matr-scalar-prod a (rest m))))))
And now a simple test on the data as in the other answer:
> (define m '((3 3 3)(5 3 4)(4 4 4)))
> m
'((3 3 3) (5 3 4) (4 4 4))
> (matr-scalar-prod 3 m)
'((9 9 9) (15 9 12) (12 12 12))
HHi, I'd highly recommend you to use Python instead of Scheme for writing GIMP scripts, unless you want to learn Scheme for recreational purposes.
One of the tenets in Python is to not allow the language to stay between you and your problem, and writing your own Matrix manipulation code is trivial. If you want high performance ops, you can use a third party library such as NumPy (even from inside GIMP environment) to get it.
So, for a Matrix class that would allow scallar multiplication and adding one could simply write:
class Matrix(object):
def __init__(self, rows, cols, *args):
self.rows = rows
self.cols = cols
self.values = args
def __getitem__(self, (i,j)):
return self.values[i * self.cols + j]
def __setitem__(self,(i,j), value):
self.values[i * self.cols + j] = value
def __add__(self, other):
values = []
for i in range(self.rows):
for j in range(self.cols):
values.append(self[i,j] + other[i,j])
return Matrix(self.rows, self.cols, *values)
def __mul__(self, N):
return Matrix(self.rows, self.cols,*(N * v for v in self.values))
def __repr__(self):
return "\n".join (" ".join(str(self[i,j]) for j in range(self.cols)) for i in range(self.rows) )
Example on Python's interactive console:
>>> m = Matrix(3,3,
... 3,3,3,
... 5,3,4,
... 4,4,4)
>>> m * 3
9 9 9
15 9 12
12 12 12
Implementing more operations is equally simple, and, for calling GIMP's API functions, with this example class, you can just use m.values, that is simply a list with all the matrix values in sequence - which is the way GIMP PDB's functions use them. (Such as pdb.gimp_drawable_transform_matrix or pdb.plug_in_convmatrix. (I suppose you've found GIMP's API browser under the help menu - the same functions are available in Scheme and in Python, just replace the "-" in the names for "_")