Subject: `guix search` does unexpected logical and

From: zimoun <[email-masked]>
Date: Mon, 22 Jul 2019 19:11:50 +0200

Dear,

As discussed here [1], the `relevance` in `guix/ui.scm` does not match
"inter-field".

Attached a fix.
Now,  the example from the manual
  $ guix search crypto library | \
        recsel -e '! (name ~ "^(ghc|perl|python|ruby)")' -p name,synopsis
outputs the expected crypto libraries as `libb2`.

Please comment. :-)

Then, please indicate me how the commit has to be filled.
The commit 8874faaaac665100a095ef25e39c9a389f5a397f introducing the
logical AND says:

ui: 'relevance' considers regexps connected with a logical and.

* guix/ui.scm (relevance)[score]: Change to return 0 when one of REGEXPS
doesn't match.
* tests/ui.scm ("package-relevance"): New test.

Should another test be added?

[1] https://lists.gnu.org/archive/html/guix-devel/2019-07/msg00263.html

Thank you in advance,
simon
diff --git a/guix/ui.scm b/guix/ui.scm
index 7920335928..0e60eb6edc 100644
--- a/guix/ui.scm
+++ b/guix/ui.scm
@@ -1291,23 +1291,36 @@ score, the more relevant OBJ is to REGEXPS."
                                     5             ;exact match
                                     1)))))
            regexps))
-
+    scores)
+
+  (define (update relevance weight scores)
+    (map + relevance
+           (map (lambda (score)
+                  (* weight score))
+                scores)))
+
+  (let ((scores (fold (lambda (metric relevance)
+                        (match metric
+                          ((field . weight)
+                           (match (field obj)
+                             (#f  relevance)
+                             ((? string? str)
+                              (update relevance weight (score str)))
+                             ((lst ...)
+                              (update relevance weight
+                                      (fold (lambda (elem prev)
+                                              (if (zero? (length elem))
+                                                  prev
+                                                  (map + elem prev)))
+                                            (make-list (length regexps) 0)
+                                            (map score lst)))
+                              )))))
+                      (make-list (length regexps) 0)
+                      metrics)))
     ;; Return zero if one of REGEXPS doesn't match.
     (if (any zero? scores)
         0
-        (reduce + 0 scores)))
-
-  (fold (lambda (metric relevance)
-          (match metric
-            ((field . weight)
-             (match (field obj)
-               (#f  relevance)
-               ((? string? str)
-                (+ relevance (* (score str) weight)))
-               ((lst ...)
-                (+ relevance (* weight (apply + (map score lst)))))))))
-        0
-        metrics))
+        (reduce + 0 scores))))
 
 (define %package-metrics
   ;; Metrics used to compute the "relevance score" of a package against a set