Are '(true nil) and '(true) is equal?

Started by IVShilov, April 10, 2019, 07:22:41 AM

Previous topic - Next topic

IVShilov

May be I don't understand recursive comparision doing by "=", but I see no logic in this:
newLISP v.10.7.1 32-bit on Windows IPv4/6 UTF-8 libffi, options: newlisp -h
> (= '(true) '(true nil))
nil
> (= '(true nil) '(true))
true

And another case on numbers:
> (= '(1 0) '(1)) #-> true?
nil
>

Bug or feature?

rickyboy

#1
Looks like a bug to me.  At the very least, I believe that it should be a desirable property for the `=` operator to act as a symmetric relation, that is, that `(= a b)` and `(= b a)` return the same boolean value (for any `a` and `b`).



More fundamentally, the manual says that for all the relational operators: "List expressions can also be compared (list elements are compared recursively)."  Your example of `(= '(true nil) '(true))` evaluating to `true` contradicts that assertion.



Nice find, BTW!
(λx. x x) (λx. x x)

rickyboy

#2
Another way to exhibit the problem:


> (= '(1 2 3 nil nil) '(1 2 3))
true
> (= '(1 2 3 nil nil nil) '(1 2 3))
true
> (= '(1 2 3 nil nil nil nil) '(1 2 3))
true
> ;; and so on ...

In nl-math.c, when the evaluation of any of the above expressions gets to `compareLists()` and `left` has the `nilSymbol`. `right` has the `nilCell` (because it's "bottomed out" already).  Then when `compareCells(left, right)` is called, it happily reports "equal!" because `isNil(left)` (nl-math.c:1034) and `isNil(right)` (nl-math.c:1036) are both true.  This is because, the `isNil()` macro doesn't distinguish between `nilSymbol` ("nil") and `nilCell` (the "end of a list" marker):


newlisp.h:450:#define isNil(A) ((A)->type == CELL_NIL || ((A)->type == CELL_SYMBOL && (A)->contents == (UINT)nilSymbol))
Lutz, all the best fixing this, because I know you don't want the fix to break the behavior of the other comparison operators.
(λx. x x) (λx. x x)

Lutz

#3
Thanks for the discovery of this bug.



Fixed here: http://newlisp.nfshost.com/downloads/development/inprogress/">http://newlisp.nfshost.com/downloads/de ... nprogress/">http://newlisp.nfshost.com/downloads/development/inprogress/

IVShilov

#4
Thank you for exhaustive answer!

IVShilov

#5
Quote from: "Lutz"Thanks for the discovery of this bug.

Fixed here: http://newlisp.nfshost.com/downloads/development/inprogress/">http://newlisp.nfshost.com/downloads/de ... nprogress/">http://newlisp.nfshost.com/downloads/development/inprogress/

Thank you for nifty tool, Lutz!

NL is my pet language.



Two more questions:

1. does
(letn (L '((1 2 3) (1 2 ))) (= L (transpose (transpose L)))) -> nil
 have the same roots? Because L is not two-dimensional matrix, there must be an exception error, no?



2. I'm newbie in compiling on Windows, so please point me to HOWTO make newlisp.exe from sources from "http://newlisp.nfshost.com/downloads/development/inprogress/">http://newlisp.nfshost.com/downloads/de ... nprogress/">http://newlisp.nfshost.com/downloads/development/inprogress/". I need MinGW?

Lutz

#6

> (set 'L '((1 2 3) (1 2 )))
((1 2 3) (1 2))
> (transpose L)
((1 1) (2 2) (3 nil))
> (transpose (transpose L))
((1 2 3) (1 2 nil))
> (= L (transpose (transpose L)))
nil
>

From the documentation of transpose :



"Any kind of list-matrix can be transposed. Matrices are made rectangular by filling in nil for missing elements, omitting elements where appropriate, or expanding atoms in rows into lists."



So this is on purpose and makes the function more usable but also will correctly make the double transposed list different from the original.



Downloads for an upcoming 10.7.5 later this spring: http://www.newlisp.org/downloads1075/">http://www.newlisp.org/downloads1075/



Ps: this is an 'unofficial' directory page, it might change before the actual release of v10.7.5.

IVShilov

#7
Ok, I understand and agree with you, add a nil to make args properly for transposition is right decision - I can filter this nil later.



But today I found that data lost because of args not matrix:
> (transpose '((1) (1 2)))
((1 1))
> (transpose (transpose '((1) (1 2))))
((1) (1))

 transpose throw away "2".



On a 2d-matrix, transpose is reversible:
> (transpose (transpose '((1 nil) (1 2))))
((1 nil) (1 2))


May be some kind of "matrix?" predicate will be useful?


Quote from: "Lutz" Downloads for an upcoming 10.7.5 later this spring: http://www.newlisp.org/downloads1075/">http://www.newlisp.org/downloads1075/
- thank you! Hope that QA-tests is up to date.

Lutz

#8
From the transpose documentation:



"Matrix dimensions are calculated using the number of rows in the original matrix for columns and the number of elements in the first row as number of rows for the transposed matrix."



Looking for the shortest row in a multidimensional list would take a much longer time. So this was intentionally.

IVShilov

#9
Ok, thanks, question was silly.