Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On Fri, Feb 12, 2016 at 12:40:45PM +, Andy Bennett wrote: > Hi Peter, > > What happens when the alist argument to assoc isn't static? Does the > data analysis know the types? Hi Andy! In that case it depends on where the list comes from. In the general case (most cases, I'd say) that's impossible. Then it will simply fall back to (list-of (pair * *)) aka (list-of pair), which would be the same as it would treat all cases after my patch. I say the general case is "most cases", because a list coming from elsewhere and which may be mutated at any time has to be assumed to have contents of unknown types. If someone does a set-car! somewhere, they can completely invalidate the types we know about the list. > Which type is better for safe code > generation in the non-static data case (which I imagine to be the > general case). The more specific type is always better, and it is equivalent to the less specific type when the types aren't known. > Is there a difference between building the alist up dynamically with > alist-cons compared to using quasiquote or cons or something? I don't think there's a difference there, because (after the fix in my patch), the types of lists created by alist-cons are known just like for regular old cons. Cheers, Peter signature.asc Description: Digital signature ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
Hi Peter, > It occurred to me that maybe the scrutinizer is smart enough to merge > lists of pairs of (known) mixed types, and it actually is! > > (use srfi-1) > (print (assoc 'x '((1 . 2) (#f . 4)) (lambda (x y) (> x y > > When compiled, this will tell you: > Warning: at toplevel: > (test.scm:2) in procedure call to `assoc', expected argument #3 of type > `(procedure ((or false fixnum) symbol) *)', but was given an argument of type > `(procedure (number number) boolean)' > > So I guess my patch needlessly weakens the type declarations. What happens when the alist argument to assoc isn't static? Does the data analysis know the types? Which type is better for safe code generation in the non-static data case (which I imagine to be the general case). Is there a difference between building the alist up dynamically with alist-cons compared to using quasiquote or cons or something? Regards, @ndy -- andy...@ashurst.eu.org http://www.ashurst.eu.org/ 0290 DA75 E982 7D99 A51F E46A 387A 7695 7EBA 75FF signature.asc Description: OpenPGP digital signature ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On Fri, Feb 12, 2016 at 08:50:21AM +0100, Peter Bex wrote: > It occurred to me that maybe the scrutinizer is smart enough to merge > lists of pairs of (known) mixed types, and it actually is! > > (use srfi-1) > (print (assoc 'x '((1 . 2) (#f . 4)) (lambda (x y) (> x y > > When compiled, this will tell you: > Warning: at toplevel: > (test.scm:2) in procedure call to `assoc', expected argument #3 of type > `(procedure ((or false fixnum) symbol) *)', but was given an argument of type > `(procedure (number number) boolean)' > > So I guess my patch needlessly weakens the type declarations. I'll send > a new patch before next week that applies the same kind of aggressively > specific type to the alist procedures. With the attached patch, you get the same message, but with the arguments reversed which is, as discussed, more consistent: Warning: at toplevel: (test.scm:3) in procedure call to `assoc', expected argument #3 of type `(procedure (symbol (or false fixnum)) *)' but was given an argument of type `(procedure (number number) boolean)' And if you change srfi-1 to data-structures, and assoc to rassoc, the current master doesn't give a compile time warning, but with this patch you'll get the same warning with both CHICKEN versions: Warning: at toplevel: (test.scm:2) in procedure call to `rassoc', expected argument #3 of type `(procedure (symbol (or false fixnum)) *)' but was given an argument of type `(procedure (number number) boolean)' Now, whether the signature of "rassoc" should differ from that of "assoc" in core is another matter. But at least we get better error checking now, and potentially better performance too. I've also simplified the (forall (a b) ...) for memq, memv and the CHICKEN 5 version of member to (forall (a) ...), because the "a" type didn't add anything. For those procedures accepting a comparison procedure, it does matter, so there I've kept it. I've augmented the type information for rassoc, alist-cons, alist-copy, and alist-delete[!] so the types are very precise. I also noticed that alist-update included an extra argument in its type after the comparison procedure, which the code does not accept, so I've removed that as well. Cheers, Peter From c54596f61348e5fb39441b0f42bb9ade2fbe8c21 Mon Sep 17 00:00:00 2001 From: Peter BexDate: Fri, 12 Feb 2016 20:17:03 +0100 Subject: [PATCH] Fix type signatures of a few alist procedures. Thanks to Joerg Wittenberger for pointing out that the types weren't exactly right. This also makes the types and higher order procedures consistent in how they call their argument predicates: always the supplied key first, and the "thing in the list" second. Conflicts: types.db --- data-structures.scm | 6 +++--- types.db| 45 - 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/data-structures.scm b/data-structures.scm index 65fdad7..f6726ee 100644 --- a/data-structures.scm +++ b/data-structures.scm @@ -223,7 +223,7 @@ (let loop ([lst lst]) (and (pair? lst) (let ([a (##sys#slot lst 0)]) - (if (and (pair? a) (cmp (##sys#slot a 0) x)) + (if (and (pair? a) (cmp x (##sys#slot a 0))) a (loop (##sys#slot lst 1)) ) ) ) ) ) ] ) ] [item (aq x lst)] ) @@ -243,7 +243,7 @@ (let ((a (##sys#slot lst 0))) (cond ((not (pair? a)) (error 'alist-update "bad argument type" a)) - ((cmp (##sys#slot a 0) k) + ((cmp k (##sys#slot a 0)) (cons (cons k v) (##sys#slot lst 1))) (else (cons (cons (##sys#slot a 0) (##sys#slot a 1)) @@ -261,7 +261,7 @@ ((pair? lst) (let ((a (##sys#slot lst 0))) (##sys#check-pair a 'alist-ref) - (if (cmp (##sys#slot a 0) x) + (if (cmp x (##sys#slot a 0)) a (loop (##sys#slot lst 1)) ) )) (else (error 'alist-ref "bad argument type" lst)) ) ) ) ) ) ) diff --git a/types.db b/types.db index c902bac..b5a5333 100644 --- a/types.db +++ b/types.db @@ -179,22 +179,19 @@ (reverse (forall (a) (#(procedure #:clean #:enforce) reverse ((list-of a)) (list-of a))) ((null) (null) (let ((#(tmp) #(1))) '( -(memq (forall (a b) (#(procedure #:clean #:foldable) memq -(a (list-of b)) -(or false (list-of b +(memq (forall (a) (#(procedure #:clean #:foldable) memq (* (list-of a)) + (or false (list-of a ((* null) (let ((#(tmp) #(1))) '#f)) ((* list) (##core#inline "C_u_i_memq" #(1) #(2 -(memv (forall (a b) (#(procedure #:clean #:foldable) memv -(a (list-of b)) -(or false (list-of b +(memv (forall (a) (#(procedure #:clean #:foldable) memv (* (list-of a)) + (or false (list-of a ((* null) (let ((#(tmp) #(1))) '#f)) (((or symbol procedure immediate) list)
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On Fri, Feb 12, 2016 at 08:34:15PM +0100, Peter Bex wrote: > And if you change srfi-1 to data-structures, and assoc to rassoc, > the current master doesn't give a compile time warning, but with this > patch you'll get the same warning with both CHICKEN versions: > > Warning: at toplevel: > (test.scm:2) in procedure call to `rassoc', expected argument #3 of type > `(procedure (symbol (or false fixnum)) *)' but was given an argument of type > `(procedure (number number) boolean)' Interestingly enough, CHICKEN 5 gives this warning only at lower optimization levels. With -O3 and higher, the warning goes away(!) I'm not sure what causes this it doesn't seem to be caused by #:foldable because if I remove it, the warning is still gone, and because the same happens with the "sort" procedure from data-structures, which doesn't have #:foldable: (use data-structures) (print (sort '(x y z) (lambda (a b) (> a b With -O2 or lower: Warning: at toplevel: (/tmp/test.scm:5) in procedure call to `chicken.data-structures#sort', expected argument #2 of type `(procedure (symbol symbol) *)' but was given an argument of type `(procedure (number number) boolean)' With -O3 or higher, no output! CHICKEN 4 doesn't have this problem. Anyway, it is a separate issue to the types.db patch but I just wanted to mention it so you don't wonder why the warning doesn't show up. I've created ticket #1258 so we won't forget to fix this before we make a release. Cheers, Peter signature.asc Description: Digital signature ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On Thu, Feb 11, 2016 at 10:06:13PM +0100, Peter Bex wrote: > On Thu, Jan 14, 2016 at 03:14:50PM +0100, Jörg F. Wittenberger wrote: > > Hi all, > > > > the srfi document wants a different type for alist-delete! than types.db > > declares. > > After all the discussion at the start, this thread kind of petered out. > So let's try again. Attached is a patch that got a bit larger as I was > working on it and spotted more and more inconsistencies and problems: > > 1) The types declared for memq, memv, member, assq, assv and [r]assoc > were also too specific, asserting that they accepted a list of pairs of > the same object types in each car and the same object types in > each cdr of the pairs in the list. Especially the type for assoc > was ambitious but completely wrong :) It occurred to me that maybe the scrutinizer is smart enough to merge lists of pairs of (known) mixed types, and it actually is! (use srfi-1) (print (assoc 'x '((1 . 2) (#f . 4)) (lambda (x y) (> x y When compiled, this will tell you: Warning: at toplevel: (test.scm:2) in procedure call to `assoc', expected argument #3 of type `(procedure ((or false fixnum) symbol) *)', but was given an argument of type `(procedure (number number) boolean)' So I guess my patch needlessly weakens the type declarations. I'll send a new patch before next week that applies the same kind of aggressively specific type to the alist procedures. Cheers, Peter signature.asc Description: Digital signature ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On Thu, Jan 14, 2016 at 03:14:50PM +0100, Jörg F. Wittenberger wrote: > Hi all, > > the srfi document wants a different type for alist-delete! than types.db > declares. After all the discussion at the start, this thread kind of petered out. So let's try again. Attached is a patch that got a bit larger as I was working on it and spotted more and more inconsistencies and problems: 1) The types declared for memq, memv, member, assq, assv and [r]assoc were also too specific, asserting that they accepted a list of pairs of the same object types in each car and the same object types in each cdr of the pairs in the list. Especially the type for assoc was ambitious but completely wrong :) 2) I noticed a lot of these alist- procedures were marked "#:enforce", but they won't enforce that the list is a proper list, nor that it contains only pairs: If it can stop early it will, without verifying anything after the found pair. The "assoc" definition didn't have this annotation, which I think is correct, so I've also removed it from the others. 3) I've made the types of all higher order alist and list traversing procedures such that the predicate receives the argument that was passed by the user first, and the thing in the list that it's comparing against second. This meant I had to change two procedure bodies in data-structures.scm. We had a short discussion about this on IRC, and we concluded that SRFI-1 is explicit about argument order while our data-structures documentation isn't explicit: "The comparison procedure is used to compare the element keys ki of alist's entries to the key parameter in this way: (= key ki). Thus, one can reliably remove all entries of alist whose key is greater than five with (alist-delete 5 alist <)" If this is too large a change, I'd be okay with changing the types so they're (procedure (* a) *) instead of (procedure (a *) *), but since we don't specify anything about this, I'd argue any program which relies on argument order is wrong anyway. At least this way we get a modicum of type sanity checking, which is worthwhile IMO. 4) I noticed that the type of alist-cons was completely wrong: (alist-cons a b lst) isn't equivalent to (cons a (cons b lst)), but to (cons (cons a b) lst)! Also, I took the opportunity to mark it #:pure, because it's just two conses, and cons is pure too. Come to think of it, would it be worthwhile to just rewrite it to cons calls using a "specialization" for (* * *)? The attached patches are for master and chicken-5. SRFI-1 got moved out to an egg for chicken-5, so if this commit is applied, the srfi-1 changes should (probably manually?) be extracted and applied to the srfi-1 egg as well. Cheers, Peter From 1279b315c5e5df2f41b5554d0cf07f1531090b17 Mon Sep 17 00:00:00 2001 From: Peter BexDate: Thu, 11 Feb 2016 21:48:56 +0100 Subject: [PATCH] Fix type signatures of a few alist procedures. Thanks to Joerg Wittenberger for pointing out that the types weren't exactly right. This also makes the types and higher order procedures consistent in how they call their argument predicates: always the supplied key first, and the "thing in the list" second. Conflicts: types.db --- data-structures.scm | 6 +++--- types.db| 45 +++-- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/data-structures.scm b/data-structures.scm index 65fdad7..f6726ee 100644 --- a/data-structures.scm +++ b/data-structures.scm @@ -223,7 +223,7 @@ (let loop ([lst lst]) (and (pair? lst) (let ([a (##sys#slot lst 0)]) - (if (and (pair? a) (cmp (##sys#slot a 0) x)) + (if (and (pair? a) (cmp x (##sys#slot a 0))) a (loop (##sys#slot lst 1)) ) ) ) ) ) ] ) ] [item (aq x lst)] ) @@ -243,7 +243,7 @@ (let ((a (##sys#slot lst 0))) (cond ((not (pair? a)) (error 'alist-update "bad argument type" a)) - ((cmp (##sys#slot a 0) k) + ((cmp k (##sys#slot a 0)) (cons (cons k v) (##sys#slot lst 1))) (else (cons (cons (##sys#slot a 0) (##sys#slot a 1)) @@ -261,7 +261,7 @@ ((pair? lst) (let ((a (##sys#slot lst 0))) (##sys#check-pair a 'alist-ref) - (if (cmp (##sys#slot a 0) x) + (if (cmp x (##sys#slot a 0)) a (loop (##sys#slot lst 1)) ) )) (else (error 'alist-ref "bad argument type" lst)) ) ) ) ) ) ) diff --git a/types.db b/types.db index c902bac..9d94746 100644 --- a/types.db +++ b/types.db @@ -179,46 +179,39 @@ (reverse (forall (a) (#(procedure #:clean #:enforce) reverse ((list-of a)) (list-of a))) ((null) (null) (let ((#(tmp) #(1))) '( -(memq (forall (a b) (#(procedure #:clean #:foldable) memq -(a (list-of b)) -(or false (list-of b +(memq (forall (a) (#(procedure #:clean
[Chicken-hackers] PATCH: wrong type for alist-delete!
Hi all, the srfi document wants a different type for alist-delete! than types.db declares. Patch attached. >From 5834292305ac4882484169104535c72981e0167b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20F=2E=20Wittenberger?=Date: Thu, 14 Jan 2016 15:12:26 +0100 Subject: [PATCH] Fix type of alist-delete! according to srfi-1 spec. --- types.db | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types.db b/types.db index f259673..2491131 100644 --- a/types.db +++ b/types.db @@ -1854,7 +1854,7 @@ (alist-cons (forall (a b c) (#(procedure #:clean) alist-cons (a b (list-of c)) (pair a (pair b (list-of c)) (alist-copy (forall (a) (#(procedure #:clean #:enforce) alist-copy ((list-of a)) (list-of a (alist-delete (forall (a b) (#(procedure #:enforce) alist-delete (a (list-of b) #!optional (procedure (a b) *)) list))) -(alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a (list-of b) #!optional (procedure (a b) *)) undefined))) +(alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a (list-of b) #!optional (procedure (a b) *)) list))) (any (forall (a) (#(procedure #:enforce) any ((procedure (a #!rest) *) (list-of a) #!rest list) *))) (append! (#(procedure #:enforce) append! (#!rest list) list)) -- 2.6.2 ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On 2016-01-14 15:14, Jörg F. Wittenberger wrote: > the srfi document wants a different type for alist-delete! than types.db > declares. > > Patch attached. Looks good to me. Debatably it ought to have an undefined return value, as with typical destructive update procedures, but hey. Signoff attached. Evan >From 061cfad9022d823a04dac69d1d766e8bd492118a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20F=2E=20Wittenberger?=Date: Thu, 14 Jan 2016 15:12:26 +0100 Subject: [PATCH] Fix type of alist-delete! according to srfi-1 spec. Signed-off-by: Evan Hanson --- types.db | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types.db b/types.db index f259673..2491131 100644 --- a/types.db +++ b/types.db @@ -1854,7 +1854,7 @@ (alist-cons (forall (a b c) (#(procedure #:clean) alist-cons (a b (list-of c)) (pair a (pair b (list-of c)) (alist-copy (forall (a) (#(procedure #:clean #:enforce) alist-copy ((list-of a)) (list-of a (alist-delete (forall (a b) (#(procedure #:enforce) alist-delete (a (list-of b) #!optional (procedure (a b) *)) list))) -(alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a (list-of b) #!optional (procedure (a b) *)) undefined))) +(alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a (list-of b) #!optional (procedure (a b) *)) list))) (any (forall (a) (#(procedure #:enforce) any ((procedure (a #!rest) *) (list-of a) #!rest list) *))) (append! (#(procedure #:enforce) append! (#!rest list) list)) -- 2.6.4 ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On Fri, Jan 15, 2016 at 09:00:54AM +1300, Evan Hanson wrote: > On 2016-01-14 15:14, Jörg F. Wittenberger wrote: > > the srfi document wants a different type for alist-delete! than types.db > > declares. > > > > Patch attached. > > Looks good to me. Debatably it ought to have an undefined return value, > as with typical destructive update procedures, but hey. Not for SRFI-1, where the return value should be the same as the non-destructive variant: "alist-delete! is the linear-update variant of alist-delete. It is allowed, but not required, to alter cons cells from the alist parameter to construct the result." But more to the point, isn't this type wrong? (which would then technically be wrong for _all_ the alist procedures) > (alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a > (list-of b) #!optional (procedure (a b) *)) list))) If I have an alist '((1 . x) (2.0 . y) (foo . 3)), then the type is "(list-of pair)", and you can't get any more precise than that I think. The types of the keys are mixed, which is somewhat weird but it's allowed in an alist. Anyway, in the above type signature, if the list is of type (list-of pair), then "b" is "pair". However, the procedure receives (a b) as arguments. That's incorrect: it wouldn't receive the PAIRS in the list, but the KEYS (so alternating, a fixnum, flonum and symbol). Usually you'd pass a comparison procedure that accepts only keys of the same type, but as you can see above that's not necessarily the case (this example works fine if we use EQUAL? as the procedure). I'm not 100% sure what the type should be though. Perhaps something like this? (alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a (list-of pair) #!optional (procedure (a b) *)) (list-of pair I kept the b in there to indicate that the comparison procedure doesn't necessarily receive two arguments of the same type. Thoughts? Cheers, Peter signature.asc Description: Digital signature ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On 2016-01-14 21:32, Peter Bex wrote: > Not for SRFI-1, where the return value should be the same as the > non-destructive variant: Right -- I meant srfi-1's API itself might be different. The "list" return isn't incorrect, but it's also not as specific as it could be. "(list-of pair)" would indeed be better. Evan signature.asc Description: PGP signature ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
Evan Hanson scripsit: > Looks good to me. Debatably it ought to have an undefined return value, > as with typical destructive update procedures, but hey. Not how linear-update works: the !-less version is pure, the ! version is not pure (or at least may not be pure). In any case, the data structure being changed is what is returned. A number of SRFIs work like this. -- John Cowan http://www.ccil.org/~cowanco...@ccil.org What is the sound of Perl? Is it not the sound of a [Ww]all that people have stopped banging their head against? --Larry ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
Peter Bex scripsit: > (alist-delete! (forall (a b) (#(procedure #:enforce) alist-delete! (a > (list-of pair) #!optional (procedure (a b) *)) (list-of pair That seems right, but isn't b here equivalent to star? -- John Cowan http://www.ccil.org/~cowanco...@ccil.org Verbogeny is one of the pleasurettes of a creatific thinkerizer. --Peter da Silva ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers
Re: [Chicken-hackers] PATCH: wrong type for alist-delete!
On 2016-01-14 16:10, John Cowan wrote: > Evan Hanson scripsit: > > Looks good to me. Debatably it ought to have an undefined return value, > > as with typical destructive update procedures, but hey. > > Not how linear-update works: the !-less version is pure, the ! version is > not pure (or at least may not be pure). In any case, the data structure > being changed is what is returned. A number of SRFIs work like this. Indeed, though that's not what the "!" convention means to me at first glance. When I see a bang, I think guaranteed destructive update, not linear-update. Of course, with lists you can't always do that, hence the bangs and specified optionality. IIRC there's some discussion of exactly this in the srfi-1 archives. I just wish linear-update used a different naming convention. Evan ___ Chicken-hackers mailing list Chicken-hackers@nongnu.org https://lists.nongnu.org/mailman/listinfo/chicken-hackers