0

I'm trying to create a game in (Simply) Scheme where read-line takes a user's input and does something accordingly. To troubleshoot, I used trace to see what each of my procedures was "thinking":

(trace eq?)
(trace string-downcase)
(trace word->string)
(trace first)
(trace read-line)

Now here's what happens when I enter "yes" into read-line when it asks me to:

> (eq? (string-downcase (word->string (first (read-line)))) "yes")
>(read-line)
yes
<'(yes)
>(first '(yes))
<'yes
>(word->string 'yes)
<"yes"
>(string-downcase "yes")
<"yes"
>(eq? "yes" "yes")
<#f
#f

When I run (eq? "yes" "yes") by itself, it returns #t like it's supposed to, but here it doesn't for some reason. I have some suspicion that it is to do with word->string's definition. This completely breaks my game; if the user inputs yes, it will act as if they entered no. Please tell me any ideas you have as to why this is happening!

YowE3K
  • 23,852
  • 7
  • 26
  • 40
Aviv Shai
  • 997
  • 1
  • 8
  • 20
  • Possible duplicate of [What is the difference between eq?, eqv?, equal?, and = in Scheme?](https://stackoverflow.com/questions/16299246/what-is-the-difference-between-eq-eqv-equal-and-in-scheme) – Alexis King Sep 28 '17 at 23:30

2 Answers2

2

When I run (eq? "yes" "yes") by itself, it returns #t like it's supposed to

No. Your assumption is wrong. eq? is not guaranteed to have any particular behavior on strings.

R5RS defines eq? on non-empty strings to use the same rules as eqv?. In turn, it states that eqv? must return #t on two strings, obj1 and obj2, when:

obj1 and obj2 are pairs, vectors, or strings that denote the same locations in the store (section 3.4).

The notion of “the store” is very loosely defined and implementation-dependent. Essentially, eq? on strings is implementation-defined. You almost always want equal?, instead, which performs actual value equality (rather than reference equality), or string=?, which specifically checks equality on strings.

Alexis King
  • 43,109
  • 15
  • 131
  • 205
  • Thank you for your solution and for that link, that really cleared things up! I did not realize there was a difference between =, eq?, equal?, etc. The problem is fixed now! – Aviv Shai Sep 28 '17 at 23:37
1

A string is stored as a vector of chars. eq? is the identity procedure and thus it checks if two argument is the same object. Multiple variable pointed to the same Object, thus created at one instance of time for a single threaded implementation, are eq?.

There is one exception. Literals in code can be cached such that objects that are created differently every time they are made can be made once for every occurrence in the code. Other languages does the same, eg. Java has a string literal pool where "yes" == "yes" would be true but of course ("y" + "es") == "yes" would be false since the left hand side is a new string with the same chars and not the same object as "yes" from the literal pool.

This is true for all literals. '(some list) or "some literal string" compared with eq? might give #t where #f would be the answer had one side been created at runtime and not by a literal. (eg. make-string) or list)

the rule of thumb

Use eqv? or the special numeric comparison procedures (=, <, ...) for numbers. Numbers are the only data type where the implementaion are allowed to copy values to a different form at any time and thus the same number might be #f with eq? even if it seems like the same object. eqv? are guaranteed to be #t for every comparison that are eq?.

Except for numbers you use eq? if you want to know if two things are created at the same time. (the same object). Eg. finding a specific node form a tree in a assoc of seen elements are typical eq? moment. Symbols are the only literals guaranteed to be #t for the same symbol.

You should use equal? if you want to know if two things look the same. equal? is guaranteed to be #t for every comparison that is eqv?. If you are sure you have strings you can use string=? for case sensitive comparison (like equal? does) and string-ci=? for case insensitive comparison.

Note that a string and a symbol don't look the same. One has the form "yes" and the other yes in the REPL.

Community
  • 1
  • 1
Sylwester
  • 47,942
  • 4
  • 47
  • 79