How can automatically identify or allow the user of my program to identify variables in Lisp?

Viewed 73

I have something of a subtle (I think) problem in Lisp, related to an earlier question I asked: How do I name a variable after a string in Lisp?

Here's how it goes:

  1. I'm creating a language in which (among other things) the user inputs text strings, and my parser then creates uniquely-identified entity (and other stuff) based on their input.
  2. A typical and simple input would be: my_name:my_contents -- where my_name is the name of the entity, and my_contents is a string.
  3. So, I need to find a way to set up a lisp program that takes the user input, then creates the entities and identifies them based on the user's input.

So far I've considered two approaches:

  • A. One variable per entity: when the user enters a string, Lisp takes my_name and creates a variable with that name, and puts my_contents inside. The drawback here is that I can't figure out how to set the name of the variable to some user-defined and mutable input such as my_name.

  • B. A table, such as a hash-table: when the user enters a string, Lisp adds a row to a hash table with my_name as the key and my_contents as the entry. The drawback with this approach is that again I can't find a way to set the key as my_name at any given moment.

In summary, I'm looking for counsel on 1. how to name a variable after a user-defined string or 2. how to set a user-defined string as a key in a hash table or 3. whether there's a better approach.

Thanks in advance!

2 Answers

If you're feeling confused, I suggest you breakdown your plan into smaller pieces. Or just use the repl to play with the ideas, that way you'll see many of your questions answered.

Start: create a hash table:

>> (make-hash-table)
;;... some hash table is created ...

N.B. below, you'll see that this type of hash table won't work with your string keys, but keep going:

wait, you need to refer to it, let's set it to a variable:

>> (setf my-hash *)

or similar:

>> (setf my-hash (make-hash-table))

add some values:

>> (setf (gethash "key1" my-hash) "value1")
>> (setf (gethash "key2" my-hash) "value2")

hmm, I'd like to see the values. There are a few options. Let's check CLHS for one of them: http://clhs.lisp.se/Body/f_maphas.htm#maphash

Copy-paste the last line of the example:

>> (maphash #'(lambda (k v) (print (list k v))) my-hash)
("key1" "value1")
("key2" "value2")
NIL

Now I wonder if I can use gethash to reach entries:

>> (gethash "key1" my-hash)
NIL

I can't! That's because make-hash-table we used above defaults to using 'eql as the test predicate. We need to change that. Do everything again with a better suited hash table:

>> (setf my-hash (make-hash-table :test 'equal))
>> (setf (gethash "key1" my-hash) "value1")
>> (setf (gethash "key2" my-hash) "value2")
>> (maphash #'(lambda (k v) (print (list k v))) my-hash)
("key1" "value1")
("key2" "value2")
>> (gethash "key1" my-hash)
"value1"

that's better.

Forgive me for starting from basics before coming to your question. I felt like we sometimes forget the principles / basics. If you play with your repl like this, I guess you'll find that it'll be easier to find some of the answers you're looking for.

And now, to add to Numbra's answer, here is some pointers:

if you want to use hash tables:

>> (setf user-entered-string "VARIABLE1")
>> (setf user-entered-value "value1")
>> (setf (gethash user-entered-string) user-entered-value)

or, symbols:

>> (intern user-entered-string)
;; now it is a symbol object in current package:
>> (find-symbol user-entered-string)
>> (setf (symbol-value (find-symbol user-entered-string)) user-entered-value)

I'm not sure to understand all of your problems, but:

Name a variable after a user-defined string:

The function that (more or less) does that is intern (or read, but that is way more general). You probably want to intern things in a "user package", so as not to conflict with the actual code.

Hash-tables

Here, I am not sure to really understand what it is that causes you troubles: if the user enters a string (that you can get with e.g. read-line or something more complex if you wish), bound in your code to, say, user-string-name, you can just do (setf (gethash user-string-variable *user-defined-variables*) user-string-value), assuming you have created such a hash-table. Note that by default, hash-tables use eql to compare keys, which is not what you want for strings; you'll need to create the table with the argument :test 'equal.

Other option

Using symbol property lists.


There are probably even more solutions that I haven't thought of. Deciding which of those is the best probably depends on many things, and I'll let you decide, given your application, which one you prefer.

Related