[plt-scheme] When does eqv? differ from eq? , from equal?

From: Jon Rafkind (workmin at ccs.neu.edu)
Date: Sun Oct 5 15:07:03 EDT 2008

Woodhouse Gregory wrote:
> I almost always perform tests with eq? or equal?, seldom (if ever) 
> with eqv? . The Reference is a bit mysterious, saying (in section 3.1)
> Two values are eqv? 
> <file:///Applications/PLT%20Scheme%20Full%20v4.1.0.3/doc/reference/booleans.html#%28def._%28%28quote._%7E23%7E25kernel%29._eqv%7E3f%29%29> 
> if and only if they are eq? 
> <file:///Applications/PLT%20Scheme%20Full%20v4.1.0.3/doc/reference/booleans.html#%28def._%28%28quote._%7E23%7E25kernel%29._eq%7E3f%29%29>, 
> unless otherwise specified for a particular datatype.
> That doesn't help much. Well, it /does/ help, but only by telling me 
> that they are usually the same. Heuristically, I think of eq? as being 
> similar to comparing pointers in C and equal? as a test that might 
> involve library call that could run in time proportional to the size 
> of the objects (e.g., strcmp). What is the intuition behind eqv?
I looked at the source for eqv and it seems to only be useful in a very 
small set of cases, mostly for numbers.
I've added some comments below:

int scheme_eqv (Scheme_Object *obj1, Scheme_Object *obj2)
  Scheme_Type t1, t2;

  /* test if the objects are eq? */
  if (SAME_OBJ(obj1, obj2))
    return 1;

  t1 = SCHEME_TYPE(obj1);
  t2 = SCHEME_TYPE(obj2);

  /* if they aren't the same type then #f */
  if (NOT_SAME_TYPE(t1, t2)) {
    /* If one is a float and the other is a double, coerce to double */
    if ((t1 == scheme_float_type) && (t2 == scheme_double_type))
      return double_eqv(SCHEME_FLT_VAL(obj1), SCHEME_DBL_VAL(obj2));
    else if ((t2 == scheme_float_type) && (t1 == scheme_double_type))
      return double_eqv(SCHEME_DBL_VAL(obj1), SCHEME_FLT_VAL(obj2));
    return 0;
  } else if (t1 == scheme_float_type) {
    return double_eqv(SCHEME_FLT_VAL(obj1), SCHEME_FLT_VAL(obj2));
  /* otherwise if the two types are double, complex, rational, or a char 
then do some equality testing, otherwise #f */
  } else if (t1 == scheme_double_type) {
    return double_eqv(SCHEME_DBL_VAL(obj1), SCHEME_DBL_VAL(obj2));
  } else if (t1 == scheme_bignum_type)
    return scheme_bignum_eq(obj1, obj2);
  else if (t1 == scheme_rational_type)
    return scheme_rational_eq(obj1, obj2);
  else if (t1 == scheme_complex_type) {
    Scheme_Complex *c1 = (Scheme_Complex *)obj1;
    Scheme_Complex *c2 = (Scheme_Complex *)obj2;
    return scheme_eqv(c1->r, c2->r) && scheme_eqv(c1->i, c2->i);
  } else if (t1 == scheme_char_type)
    return SCHEME_CHAR_VAL(obj1) == SCHEME_CHAR_VAL(obj2);
    return 0;

Posted on the users mailing list.