I evaluated the following elisp code in ielm:
(setq foo-hash (make-hash-table))
(puthash "location" "house" foo-hash)
(defun foo-start ()
(interactive)
(message (gethash "location" foo-hash)))
However when i run (foo-start) or (gethash "location" foo-hash) i get only nil echoed. Entering just foo-hash in ielm echoes: #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data ("location" "house"))
Is that a bug or i am doing something wrong?
Emacs version: 24.0.95.1
Hash tables in elisp use eql for comparison by default. Strings won't be equal with eql unless they're the same object. You probably want to use equal, which compares the contents of the strings. Create your hash table with this:
(make-hash-table :test 'equal)
Related
In short: (gethash 'PARIS pandemic-hash-table) is returning nil, despite 'PARIS being a key in the table; this seems to be related to quoting/evaluation of symbols during the hash-table creation in some way but I can't figure it out.
I'm playing with a graph search (testing for the shortest route between cities in the board game Pandemic; just for fun - trying to find optimal research lab placement in a way more sophisticated than 'has the most edges'). I'm using a hash table to hold the route data (nodes and edges), and, needed to input the data as a preliminary:
(defvar *nodes* '('San-Francisco 'Chicago 'Atlanta 'Washington 'Montreal 'New-York 'Madrid 'Paris 'London 'Essen 'Milan 'St-Petersburg))
(defvar *edges* '(('Chicago 'St-Petersburg)
('San-Francisco 'Atlanta 'Montreal)
('Chicago 'Washington)
('Atlanta 'Montreal 'New-York)
('Chicago 'Washington 'New-York)
('Montreal 'Washington 'Madrid 'London)
('New-York 'London 'Paris)
('Madrid 'Essen 'London 'Milan)
('Madrid 'Essen 'London 'New-York)
('London 'Paris 'Milan 'St-Petersburg)
('Paris 'Essen)
('Essen 'Chicago)))
(defvar *pandemic-node-hash* (make-hash-table))
(loop for node in *nodes*
for edges in *edges*
do (setf (gethash node *pandemic-node-hash*) edges))
If I look at the resulting hash table:
CL-USER> (loop for key being the hash-keys of *pandemic-node-hash*
do (print key))
'SAN-FRANCISCO
... ;other keys removed for brevity
'PARIS
NIL
So it's making the table (and the edges show up similarly), but, (gethash 'PARIS *pandemic-node-hash*) returns nil. If I then add another 'PARIS node directly (setf (gethash 'paris *pandemic-node-hash*) 'somevalue), and check the keys, I get:
(loop for key being the hash-keys of *pandemic-node-hash*
do (print key))
'other keys
'PARIS
PARIS
NIL
So, the problem has something to do with the evaluation of the symbols ('PARIS and friends) in the initial hash table creation loop, but I can't quite figure out what's going on or how to do that correctly. I'm guessing node evaluates to the un-evaluated symbol, passing that to gethash ... but what's the right way? Surely not (eval node)? Backtick the list, with commas in front of the symbols? (ugh).
Remember: 'foo is the short form for (quote foo). It's a list with two elements: the symbol CL:QUOTE and the symbol FOO.
(defun show-it (arg)
(print (list arg (type-of arg)))
(values))
Above is a smaller helper function for this answer.
CL-USER 37 > (show-it 'hamburg)
(HAMBURG SYMBOL)
Above shows that the function sees the symbol hamburg and not the value of a variable hamburg.
Not
CL-USER 38 > (show-it '('hamburg))
(((QUOTE HAMBURG)) CONS)
Above: the function sees a nested list, with a list, which has quote as a symbol.
Note: ((quote hamburg)) can be written shorter as('hamburg).
CL-USER 39 > (show-it (first '('hamburg)))
((QUOTE HAMBURG) CONS)
Above: if we get the first element, we get the list with the quote symbol.
Better
CL-USER 40 > (show-it '(hamburg))
((HAMBURG) CONS)
Above provides a list with one symbol, the symbol hamburg.
CL-USER 41 > (show-it (first '(hamburg)))
(HAMBURG SYMBOL)
Above gets the first element, which is the symbol hamburg.
Evaluation
Make sure that you understand evaluation in Lisp. quote blocks evaluation for the whole quoted expression and on all levels of those. Thus it makes no sense to quote contents inside a quoted list.
When passing arguments in a function call, then quoting is used to prevent lists and symbols to be evaluated. Thus quote creates literal data: literal symbols, literal lists, literal vectors, etc.
Thus quoting is a mechanism of code, not of data.
Code:
(first '(hamburg)) vs. (first (hamburg))
getting the first element of a literal list vs.
getting the first element of the result
of calling the function `hamburg`.
Data:
(paris hamburg berlin rome) vs. ('paris 'hamburg 'berlin 'rome)
A list of city names vs. a list of city names,
each nested in a list (quote ...)
Thus:
('paris 'hamburg 'berlin 'rome) makes no sense.
Why not
(dolist (node *nodes*)
(dolist (edges *edges*)
(setf (gethash node *pandemic-node-hash*) edges)))
But also you've double quoted your symbols (as someone else commented)
Why:
'(('Chicago 'St-Petersburg) ...)
when it should probably be just this (don't quote the list and each symbol)
'((Chicago St-Petersburg) ...)
You would see this if you evaluated: *edges*
This function resets the value for each of the specified parts of speech to NIL using putp.
The first argument is a hashtable, for this example, lets call it word-dict.
There are a variable number of parts of speech passed to resetPartsOfSpeech.
Example:
(resetPartsOfSpeech word-dict 'subject 'verb 'prep 'directObj)
(defun resetPartsOfSpeech(word-dict &rest parts)
(do ((partsVar parts (cdr partsVar)))
( (null partsVar) T)
;;; procces the car
(putp NIL word-dict (car partsVar))
))
; here is the results of the function
#S(HASH-TABLE :TEST FASTHASH-EQL (NIL . VERB) (LICKED . VERB) (HAS . VERB) (ATE . VERB) (RAN . VERB) (TAUGHT . VERB)
As you see, it only adds the NIL variable to the list, not clearing them all out.
Helper Functions I Have, The job of these two functions is to put and get data from the hashtable created.
; creating the hash table
(setf word-dict (MAKE-HASH-TABLE))
(defun putp (symbol ht value)
(if (ATOM symbol)
(setf (gethash symbol ht) value)
(ERROR "~s is not a valid symbol for putp" symbol)
))
(defun getp (symbol ht)
(gethash symbol ht) )
(defun isa(word partOfSpeech) ; this function returns T if the specified word is that specified partOfSpeech,
; otherwise, NIL is returned.
(eql (getp word word-dict) partOfSpeech))
(defun set_isa (partOfSpeech &rest words) ; this function defines each
word in the list of words to the specified partOfSpeech
; in the dictionary (hard code word-dict).
(do ((wordVar words (cdr wordVar)) )
( (NULL wordVar ) T)
;;; proccess the CAR
(putp (car wordVar) word-dict partOfSpeech)
(print (car wordVar))))
What I am having trouble understanding is that how I should go about itterating thru each value in the hash table. What I was considering was doing a nested do or dolist loop but can't quite figure out how to go about that with the values from the table, or if that is even possible.
The fundamental problem is with:
(putp NIL word-dict (car partsVar))
When putp is called, nil is bound to symbol, word-dict is bound to ht, and (car partsVar), i.e. the next symbol in the list of parts of speech, is bound to value. Within putp the expression:
(setf (gethash symbol ht) value)
becomes:
(setf (gethash 'nil word-dict) (car partsVar))
Here, (gethash 'nil word-dict) is the place that is set to the value (car partsVar). Since there is no 'nil key in the hash table yet, a new key is created and given the value (car partsVar), which is 'verb in the OP example.
In the original putp expression, (car partsVal) should have been in the symbol position as that is the key which should be updated:
(defun resetPartsOfSpeech (word-dict &rest parts)
(do ((partsVar parts (cdr partsVar)))
((null partsVar) t)
(putp (car partsVar) word-dict 'nil)))
Although this solves the problem, there is a better solution.
(defun reset-parts-of-speech (word-dict &rest parts)
(dolist (part parts)
(putp part word-dict 'nil)))
When you want to do a simple iteration over a list of elements, symbols for parts of speech in this case, just use a simple dolist. Additionally, it would be good to get into better habits with respect to Lisp style. Prefer kebab-case to camel-case; put all closing parentheses on one line (almost always); use proper indentation to make program structure clear. A good lisp-aware text editor can be most helpful for the last two.
Here is some testing in the REPL using a set-isa function based on the previous question by OP:
SCRATCH> (defvar *word-dict* (make-hash-table))
*WORD-DICT*
SCRATCH> (set-isa 'verb 'eat 'sleep 'walk)
NIL
SCRATCH> (set-isa 'noun 'cake 'ice-cream 'pizza)
NIL
SCRATCH> (gethash 'verb *word-dict*)
(WALK SLEEP EAT)
T
SCRATCH> (gethash 'noun *word-dict*)
(PIZZA ICE-CREAM CAKE)
T
SCRATCH> (set-isa 'adjective 'delicious 'sweet 'crispy)
NIL
SCRATCH> (gethash 'adjective *word-dict*)
(CRISPY SWEET DELICIOUS)
T
SCRATCH> (resetPartsOfSpeech *word-dict* 'verb)
T
SCRATCH> (gethash 'verb *word-dict*)
NIL
T
SCRATCH> (gethash 'noun *word-dict*)
(PIZZA ICE-CREAM CAKE)
T
SCRATCH> (reset-parts-of-speech *word-dict* 'adjective 'noun)
NIL
SCRATCH> (gethash 'noun *word-dict*)
NIL
T
SCRATCH> (gethash 'adjective *word-dict*)
NIL
T
Update
The above was predicated on OP statement: "This function resets the value for each of the specified parts of speech to NIL...," which seemed to suggest that OP wants the hash table to store parts of speech as keys and lists of words as the associated values. This also seems to align with a previous question posted by OP. But, after an exchange of comments, it seems that OP may prefer a hash table with individual words as keys and parts of speech as the associated values. It is unclear how words which may be associated with multiple parts of speech should be handled.
The hash table shown in OP example code #S(HASH-TABLE :TEST FASTHASH-EQL (NIL . VERB) (LICKED . VERB) ;..., along with OP comments, supports this second interpretation. If this is the case, then what does it mean to "reset each value" in the hash table to 'nil? Perhaps the sensible thing to do is to remove each entry entirely which has a value that matches a provided part-of-speech argument.
This can easily be accomplished by using dolist to loop over the list of parts of speech, and subsequently mapping over the hash table with maphash and a function that removes any entry holding a matching value:
(defun remove-parts-of-speech (word-dict &rest parts)
(dolist (part parts)
(maphash #'(lambda (k v) (if (eql v part) (remhash k word-dict)))
word-dict)))
Here is another REPL demonstration using OP's current set-isa function which populates a hash table with words for keys and parts of speech for values. After populating the hash table with nine words which are 'nouns, 'verbs, and 'adjectives, the remove-parts-of-speech function is used to remove all entries which are nouns or verbs from *word-dict*. After this, only the three adjective entries remain in the hash table.
CL-USER> (defvar *word-dict* (make-hash-table))
*WORD-DICT*
CL-USER> (set-isa 'verb 'run 'jump 'climb)
RUN
JUMP
CLIMB
T
CL-USER> (set-isa 'noun 'hat 'shoe 'scarf)
HAT
SHOE
SCARF
T
CL-USER> (set-isa 'adjective 'salty 'spicy 'sour)
SALTY
SPICY
SOUR
T
CL-USER> *word-dict*
#<HASH-TABLE :TEST EQL :COUNT 9 {1003CE10C3}>
CL-USER> (hash-table-count *word-dict*)
9
CL-USER> (remove-parts-of-speech *word-dict* 'noun 'verb)
NIL
CL-USER> (hash-table-count *word-dict*)
3
CL-USER> (gethash 'spicy *word-dict*)
ADJECTIVE
T
I have various functions and I want to call each function with the same value. For instance,
I have these functions:
(defun OP1 (arg) ( + 1 arg) )
(defun OP2 (arg) ( + 2 arg) )
(defun OP3 (arg) ( + 3 arg) )
And a list containing the name of each function:
(defconstant *OPERATORS* '(OP1 OP2 OP3))
So far, I'm trying:
(defun TEST (argument) (dolist (n *OPERATORS*) (n argument) ) )
I've tried using eval, mapcar, and apply, but these haven't worked.
This is just a simplified example; the program that I'm writing has eight functions that are needed to expand nodes in a search tree, but for the moment, this example should suffice.
Other answers have provided some idiomatic solutions with mapcar. One pointed out that you might want a list of functions (which *operators* isn't) instead of a list of symbols (which *operators* is), but it's OK in Common Lisp to funcall a symbol. It's probably more common to use some kind of mapping construction (e.g., mapcar) for this, but since you've provided code using dolist, I think it's worth looking at how you can do this iteratively, too. Let's cover the (probably more idiomatic) solution with mapping first, though.
Mapping
You have a fixed argument, argument, and you want to be able to take a function function and call it with that `argument. We can abstract this as a function:
(lambda (function)
(funcall function argument))
Now, we want to call this function with each of the operations that you've defined. This is simple to do with mapcar:
(defun test (argument)
(mapcar (lambda (function)
(funcall function argument))
*operators*))
Instead of operators, you could also write '(op1 op2 op3) or (list 'op1 'op2 'op3), which are lists of symbols, or (list #'op1 #'op2 #'op3) which is a list of functions. All of these work because funcall takes a function designator as its first argument, and a function designator is
an object that denotes a function and that is one of: a symbol (denoting the function named by that symbol in the global environment), or a function (denoting itself).
Iteratively
You can do this using dolist. The [documentation for actually shows that dolist has a few more tricks up its sleeve. The full syntax is from the documentation
dolist (var list-form [result-form]) declaration* {tag | statement}*
We don't need to worry about declarations here, and we won't be using any tags, but notice that optional result-form. You can specify a form to produce the value that dolist returns; you don't have to accept its default nil. The common idiom for collecting values into a list in an iterative loop is to push each value into a new list, and then return the reverse of that list. Since the new list doesn't share structure with anything else, we usually reverse it destructively using nreverse. Your loop would become
(defun test (argument)
(let ((results '()))
(dolist (op *operators* (nreverse results))
(push (funcall op argument) results))))
Stylistically, I don't like that let that just introduces a single value, and would probably use an &aux variable in the function (but this is a matter of taste, not correctness):
(defun test (argument &aux (results '()))
(dolist (op *operators* (nreverse results))
(push (funcall op argument) results)))
You could also conveniently use loop for this:
(defun test2 (argument)
(loop for op in *operators*
collect (funcall op argument)))
You can also do somewhat succinctly, but perhaps less readably, using do:
(defun test3a (argument)
(do ((results '() (list* (funcall (first operators) argument) results))
(operators *operators* (rest operators)))
((endp operators) (nreverse results))))
This says that on the first iteration, results and operators are initialized with '() and *operators*, respectively. The loop terminates when operators is the empty list, and whenever it terminates, the return value is (nreverse results). On successive iterations, results is a assigned new value, (list* (funcall (first operators) argument) results), which is just like pushing the next value onto results, and operators is updated to (rest operators).
FUNCALL works with symbols.
From the department of silly tricks.
(defconstant *operators* '(op1 op2 o3))
(defun test (&rest arg)
(setf (cdr arg) arg)
(mapcar #'funcall *operators* arg))
There's a library, which is almost mandatory in any anywhat complex project: Alexandria. It has many useful functions, and there's also something that would make your code prettier / less verbose and more conscious.
Say, you wanted to call a number of functions with the same value. Here's how you'd do it:
(ql:quickload "alexandria")
(use-package :alexandria)
(defun example-rcurry (value)
"Calls `listp', `string' and `numberp' with VALUE and returns
a list of results"
(let ((predicates '(listp stringp numberp)))
(mapcar (rcurry #'funcall value) predicates)))
(example-rcurry 42) ;; (NIL NIL T)
(example-rcurry "42") ;; (NIL T NIL)
(defun example-compose (value)
"Calls `complexp' with the result of calling `sqrt'
with the result of calling `parse-integer' on VALUE"
(let ((predicates '(complexp sqrt parse-integer)))
(funcall (apply #'compose predicates) value)))
(example-compose "0") ;; NIL
(example-compose "-1") ;; T
Functions rcurry and compose are from Alexandria package.
I want to do a macro in common lisp which is supposed to take in one of its arguments a list made of slots and strings. Here is the prototype :
(defclass time-info ()
((name :initarg name)
(calls :initarg calls)
(second :initarg second)
(consing :initarg consing)
(gc-run-time :initarg gc-run-time)))
(defun print-table (output arg-list time-info-list) ())
The idea is to print a table based on the arg-list which defines its structure. Here is an example of a call to the function:
(print-table *trace-output*
'("|" name "||" calls "|" second "\")
my-time-info-list)
This print a table in ascII on the trace output. The problem, is that I don't know how to explicitely get the elements of the list to use them in the different parts of my macro.
I have no idea how to do this yet, but I'm sure it can be done. Maybe you can help me :)
I would base this on format. The idea is to build a format string
from your arg-list.
I define a helper function for that:
(defun make-format-string-and-args (arg-list)
(let ((symbols ()))
(values (apply #'concatenate 'string
(mapcar (lambda (arg)
(ctypecase arg
(string
(cl-ppcre:regex-replace-all "~" arg "~~"))
(symbol
(push arg symbols)
"~a")))
arg-list))
(nreverse symbols))))
Note that ~ must be doubled in format strings in order to escape them.
The printing macro itself then just produces a mapcar of format:
(defmacro print-table (stream arg-list time-info-list)
(let ((time-info (gensym)))
(multiple-value-bind (format-string arguments)
(make-format-string-and-args arg-list)
`(mapcar (lambda (,time-info)
(format ,stream ,format-string
,#(mapcar (lambda (arg)
(list arg time-info))
arguments)))
,time-info-list)))
You can then call it like this:
(print-table *trace-output*
("|" name "||" calls "|" second "\\")
my-time-info-list)
Please note the following errors in your code:
You need to escape \ in strings.
Second is already a function name exported from the common-lisp
package. You should not clobber that with a generic function.
You need to be more precise with your requirements. Macros and Functions are different things. Arrays and Lists are also different.
We need to iterate over the TIME-INFO-LIST. So that's the first DOLIST.
The table has a description for a line. Each item in the description is either a slot-name or a string. So we iterate over the description. That's the second DOLIST. A string is just printed. A symbol is a slot-name, where we retrieve the slot-value from the current time-info instance.
(defun print-table (stream line-format-description time-info-list)
(dolist (time-info time-info-list)
(terpri stream)
(dolist (slot-or-string line-format-description)
(princ (etypecase slot-or-string
(string slot-or-string)
(symbol (slot-value time-info slot-or-string)))
stream))))
Test:
> (print-table *standard-output*
'("|" name "||" calls "|" second "\\")
(list (make-instance 'time-info
:name "foo"
:calls 100
:second 10)
(make-instance 'time-info
:name "bar"
:calls 20
:second 20)))
|foo||100|10\
|bar||20|20\
First, you probably don't want the quote there, if you're using a macro (you do want it there if you're using a function, however). Second, do you want any padding between your separators and your values? Third, you're probably better off with a function, rather than a macro.
You also seem to be using "array" and "list" interchangeably. They're quite different things in Common Lisp. There are operations that work on generic sequences, but typically you would use one way of iterating over a list and another to iterate over an array.
I'm trying to create a "dictionary" type - ie hash table with a string as a key. Is this possible or wise in Lisp?
I noticed that this works as expected:
> (setq table (make-hash-table))
#<HASH-TABLE :TEST EQL size 0/60 #x91AFA46>
> (setf (gethash 1 table) "one")
"one"
> (gethash 1 table)
"one"
However, the following does not:
> (setq table (make-hash-table))
#<HASH-TABLE :TEST EQL size 0/60 #x91AFA0E>
> table
#<HASH-TABLE :TEST EQL size 0/60 #x91AFA0E>
> (setf (gethash "one" table) 1)
1
> (gethash "one" table)
NIL
NIL
You need to make hash-table that uses 'equal instead if 'eql. 'eql doesn't evaluate two strings with same content to 't, while 'equal does.
Here is how you do it:
(make-hash-table :test 'equal)
As skypher noted you can also use 'equalp instead if you want case-insensitive string hashing.