I'm trying to take a string, and convert it into a variable name. I though (make-symbol) or (intern) would do this, but apparently it's not quite what I want, or I'm using it incorrectly.
For example:
> (setf (intern (string "foo")) 5)
> foo
5
Here I would be trying to create a variable named 'foo' with a value of 5. Except, the above code gives me an error. What is the command I'm looking for?
There are a number of things to consider here:
SETF does not evaluate its first argument. It expects a symbol or a form that specifies a location to update. Use SET instead.
Depending upon the vintage and settings of your Common Lisp implementation, symbol names may default to upper case. Thus, the second reference to foo may actually refer to a symbol whose name is "FOO". In this case, you would need to use (intern "FOO").
The call to STRING is harmless but unnecessary if the value is already a string.
Putting it all together, try this:
> (set (intern "FOO") 5)
> foo
5
Use:
CL-USER 7 > (setf (SYMBOL-VALUE (INTERN "FOO")) 5)
5
CL-USER 8 > foo
5
This also works with a variable:
CL-USER 11 > (let ((sym-name "FOO"))
(setf (SYMBOL-VALUE (INTERN sym-name)) 3))
3
CL-USER 12 > foo
3
Remember also that by default symbols are created internally as uppercase. If you want to access a symbol via a string, you have to use an uppercase string then.
Related
(apply string-replace ";" "" '("a" "b;" "c"))
gives me the error message
string-replace: arity mismatch;
the expected number of arguments does not match the given number
expected: 3 plus an optional argument with keyword #:all?
given: 5
arguments...:
As far as I understand, the problem is that the list is consed to the arguments of the string-replace function, whereas I would like to apply the function to every element of the list.
What would be the correct way to apply string-replace to a list?
(apply string-replace "b" "" '("b;"))
works, but returns "b;bb; whereas I would have expected "b".
To apply a function to all the elements of a list, use map (reference):
(map (lambda (str) (string-replace str ";" ""))
'("a" "b;" "c"))
produces
'("a" "b" "c")
Using the file "test-lexer.lisp", I have very slightly modified lex to be
(defparameter *lex* (test-lexer "{ 1.0 12 fred 10.23e12"))
and increased the number of times test repeats to 6
(defun test ()
(loop repeat 6
collect (multiple-value-list (funcall *lex*))))
and tried modifying test-lexer in a number of ways to try to get it to recognize "{" as a token.
For example, adding [:punct:] in (deflexer test-lexer ...)
by changing
("[:alpha:][:alnum:]*"
(return (values 'name %0)))
to
("[:alpha:][:alnum:][:punct:]*"
(return (values 'name %0)))
and consistently get errors like
"""Lexer unable to recognize a token in "{ 1.0 12 fred 10.23e12", position 0 ("{ 1.0 12 fred 10.23e")
[Condition of type SIMPLE-ERROR]"""
How can i specify "{" as a character to be recognized? Or is my problem elsewhere?
The cl-lexer system is based on regular expressions, so you can put any literal character to stand for itself, like {. But it happens that the brace character has a special meaning in the regular expression language, so you need to quote it with a backslash. In order to write a backslash in Lisp strings, backslashes need to be escaped. Hence:
(deflexer test-lexer
("\\{" (return (values :grouping :open-brace))) ;; <-- Here
("[0-9]+([.][0-9]+([Ee][0-9]+)?)"
(return (values 'flt (num %0))))
("[0-9]+"
(return (values 'int (int %0))))
("[:alpha:][:alnum:]*"
(return (values 'name %0)))
("[:space:]+"))
I return the :open-brace value and the :grouping category, but you can choose to return something else if you want.
The test function then returns:
((:GROUPING :OPEN-BRACE) (FLT 1.0) (INT 12)
(NAME "fred") (FLT 1.023e13) (NIL NIL))
For example, I have the following nested vector:
[[[0.582198689235419 -0.34713183143727 0.4685311493624731]
[-0.38928013774079284 -0.5901700383677557 -0.37573234072157]
[0.6716356761877877 -0.19645167952721243 -0.5700686091940252]]
[[0.0027162308840597005 -0.4483592764429284 -0.4766278022217257 -0.2724018313051576]
[-0.2765881229144672 -0.8030656496255356 -0.16159395457031567 -0.27432324260043084]
[-0.6154630466545907 -0.60573539482247 0.4417814561800192 -0.5559788990464504]
[0.6194560094536031 -0.3663074359460578 -0.5704311251195602 0.7194827876969362]]]
And I have the following flattened vector:
(0.5366343712173423
-0.816449781850872
-0.16066485785704843
0.9816561233924161
-0.09646744313584676
-0.2619662625757997
-0.9946004265996822
-0.14096299956754854
0.579260850612288
-0.827601452607939
-0.24934665032374648
-0.42272393175707873
0.11239245249400165
-0.29878238708035043
-0.61522274672097
0.8298721730401472
0.5016214138116059
0.11633537727916243
-0.0631891708267196
-0.26569217599364303
0.20900664784109668
0.2005869506108401
-0.2658279978034501
0.3383997403318165
-0.09353513546647907)
I want the flattened vector to be converted to a nested vector that follows the same structure as the nested vector presented above. Is there a core function in Clojure or a library that does this? I have some ideas of how to solve this problem, but all of them seem very very inefficient, and this operation will be used with big vectors.
Thank you very much in advance.
This was a fun question to answer, because it is one of the very few times when I think using a zipper makes things easier instead of harder. The idea is to just make a vector-zip of the nested vector, to represent the desired structure, and call zip/next on it repeatedly; whenever we get to a node which is a leaf, we replace its value with the next one from the input sequence.
Note that this assumes there are exactly as many items in the nested structure as in the flattened list; if that is not the case, you will probably get an error of some kind, who knows.
(require '[clojure.zip :as z])
(defn replace-values [structure values]
(loop [z (z/vector-zip structure)
values (seq values)]
(cond (not values) (z/root z)
(z/branch? z) (recur (z/next z) values)
:else (recur (-> z
(z/replace (first values))
(z/next))
(next values)))))
user> (replace-values '[[[0.582198689235419 -0.34713183143727 0.4685311493624731]
[-0.38928013774079284 -0.5901700383677557 -0.37573234072157]
[0.6716356761877877 -0.19645167952721243 -0.5700686091940252]]
[[0.0027162308840597005 -0.4483592764429284 -0.4766278022217257 -0.2724018313051576]
[-0.2765881229144672 -0.8030656496255356 -0.16159395457031567 -0.27432324260043084]
[-0.6154630466545907 -0.60573539482247 0.4417814561800192 -0.5559788990464504]
[0.6194560094536031 -0.3663074359460578 -0.5704311251195602 0.7194827876969362]]]
'(0.5366343712173423
-0.816449781850872
-0.16066485785704843
0.9816561233924161
-0.09646744313584676
-0.2619662625757997
-0.9946004265996822
-0.14096299956754854
0.579260850612288
-0.827601452607939
-0.24934665032374648
-0.42272393175707873
0.11239245249400165
-0.29878238708035043
-0.61522274672097
0.8298721730401472
0.5016214138116059
0.11633537727916243
-0.0631891708267196
-0.26569217599364303
0.20900664784109668
0.2005869506108401
-0.2658279978034501
0.3383997403318165
-0.09353513546647907))
[[[0.5366343712173423 -0.816449781850872 -0.16066485785704843]
[0.9816561233924161 -0.09646744313584676 -0.2619662625757997]
[-0.9946004265996822 -0.14096299956754854 0.579260850612288]]
[[-0.827601452607939 -0.24934665032374648 -0.42272393175707873 0.11239245249400165]
[-0.29878238708035043 -0.61522274672097 0.8298721730401472 0.5016214138116059]
[0.11633537727916243 -0.0631891708267196 -0.26569217599364303 0.20900664784109668]
[0.2005869506108401 -0.2658279978034501 0.3383997403318165 -0.09353513546647907]]]
Using Common Lisp I am trying loop through a list of students and if the GPA is greater than or equal to 3.0 I want to push a 1 onto another list called equal_names. The problem I am having is the interpreter keeps saying the GPA in the comparison list is "not of type (or rational float)". Why am I getting this error?
Yes, this is for homework. Also this is my first time asking on here, so if you need anything else please let me know.
Sample of the list I am getting the GPA from, where the GPA is 2.307...:
(SETQ students (LIST
(LIST (LIST 'Abbott 'Ashley 'J) '8697387888 'NONE 2.3073320999676614)))
The code I have written:
(setq gpa_count ())
(loop for x in students
if(>= 3.0 (cdr (cdr (cdr x))))
do(push '1 gpa_count))
Given a non-empty list cdr returns the tail of that list, i.e. the list that contains all the elements of the list but the first. The important thing to note is that it returns a list, not an element. That is (cdr (cdr (cdr x))) returns the list (2.30733...), not the float 2.30733.
The loop iterates the outer list. To understand the code in the loop you can look at the first element in students, which is:
'((Abbott Ashley J) 8697387888 NONE 2.3073320999676614)
Now we are going to orientate the list. Every time you pass an element add a d.
Every time you pick a value or go to a list in the list you add an a.
To find how to access the number 2.307.... You look at the first element element in the list:
(Abbott Ashley J) d
8697387888 d
NONE d
Now we are at the part that you are interested in, ie. (2.3073320999676614)), thus you add an a. Now order those in reverse and put a c in front and a r in the end.. It becomes cadddr In light of that your loop should be:
(setq students '(("Mary Larson" 333 NONE 1.1)
("Mina Morson" 333 NONE 2.5)
("Magnus Outsider" 333 NONE 4.1)))
(setq gpa_count ())
(loop for x in students
if (>= 3.0 (cadddr x))
do (push '1 gpa_count))
gpa_count ; ==> (1 1)
Another example:
(setq x (1 (2 3) (3 4 (5 6) 7))) ; ==> (1 (2 3) (3 4 (5 6) 7))
To get the 3*. We follow the parts. 1 == d, (2 3) == a, 2 ==d, 3* == a. In reverse: adad and add c and r to the ends ==> cadadr. thus:
(cadadr '(1 (2 3) (3 4 (5 6) 7))) ; ==> 3
To get the 5. we do the same 1 == d, (2 3) == d and then we have the list we want ==a.
Then 3 ==d, 4 ==d, (5 6) ==a. The 5 is the first element == a. In reverse aaddadd. Now CL guarantees 4 letters accessors so we need to split it up in 4s from the right. Thus it becomes:
(caadr (cdaddr '(1 (2 3) (3 4 (5 6) 7)))) ; ==> 5
Now, without describing you can pick any number or list. Eg. to get (5 6) ddadda, in reverse and split up becomes (cadr (cdaddr x))
Hope it helps.
If your data format is consistent then
(fourth x)
will return the GPA.
Going further,
(setf (symbol-function 'gpa)(function fourth))
would provide
(gpa x)
as "an accessor" for the gpa in the data structure.
My CLISP 2.49 gives this error message:
*** - >=: (2.307332) is not a real number
Let's look at that error message: >=: (2.307332) is not a real number.
The error happens at the call to >= and one argument is a list of a number, not a number.
Since you try to extract the number from a list, does that extract work?
We see that you call CDR. CDR of a list returns a list. So there is the error. You need to extract the number from the list.
Btw., CLISP has commands like help, where, backtrace, ... to further investigate the problem. Just type help and return, without anything else, and you see a list of commands.
How can I represent a char (character) in clojure?
Also I would like an example to test it using the char? function
(println (char? 1))
(println (char? (char 'a')))
Use a backslash for representing an individual character. For instance:
(char? \a)
returns true