guix-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Learning the match-syntax...


From: swedebugia
Subject: Re: Learning the match-syntax...
Date: Tue, 8 Jan 2019 09:25:34 +0100

On 2019-01-07 23:18, Ricardo Wurmus wrote:

Hej swedebugia,

e.g.
(match '(1 2 "y" "x")
   (1
    'one)
   (number
    'number))

Will match any number for the first clause and any string for the
second. It ONLY checks if it is a number.

This is not correct.  The first clause does not match because the number
1 is not equal to the list '(1 2 "y" "x").  So we fall through to the
next pattern.  That pattern is just the variable name “number”, which
will match absolutely anything.  “number” will be bound to '(1 2 "y"
"x") and the return value of the clause is the symbol 'number.

To actually match something e.g. the "x" literally we need to nest the
match like this:

(match '(1 2 y x)
   (string
    (match string
        ("x"
           'x!)))
   (number
    'number))

No.  Here the first pattern matches absolutely anything.  The name
“string” could be anything at all.  It’s just the name of a variable
that should be bound.  So here you first bind '(1 2 y x) to the variable
“string”, and then you try match the value of that very same variable to
the string "x", which fails.  Hence we fall through to the next clause,
where the pattern is just the variable “number”, which will bind to
absolutely anything.  So that’s what happens and the symbol 'number is
returned.

Positional arguments work like this:

(match '(1 2 y x)
   ;match the third item
   (_ _ string
    ;check if it is the literal "x"
    (match string
        ("x"
           'x!)))
   (number
    'number))

Correct?

No.  If you run this in the REPL you’ll see an error.  You have
misunderstood how match works.  Here’s another example:

(match '(1 2 x y)
   ((one two three four)
    (format #f
            "the first value is ~a, the second is ~a, the third is ~a and the fourth 
is ~a\n"
            one two three four))
   ((this will never match)
    #f))

Here we have two clauses: the first clause has the pattern

    (one two three four)

i.e. a list of four variables.  This matches the value exactly.  Each
variable is bound to one of the values of the list.

The second clause has also four variables and would match just as well,
but it will not be considered as the first pattern has already matched.

Does this make things clearer?


To match by *type* (as you tried above) you need to use predicates.
Here’s an example:

(match '(1 2 x y)
   (((? string? one) two three four)
    'will-not-match)
   ((this (? number? will) totally match)
    will))

The first pattern would only match if the first value were a string
(which would be bound to the variable “one”).  But it is not, so the
next pattern is tried.  There we want to match against four variables of
which the second needs to be a number.  This matches, so “will” is bound
to the number 2, which is what we return.

This was exactly what I needed to understand! <3

I went ahead and coded all morning and now I ported one of the medium-level procedures in guile-wikidata to use match:

(define* (get-label qid
                    #:key (language 'en))
  "Return STRING with label in the target language. Supports only one
language. Defaults to \"en\"."
  (and-let* ((l "labels")
             (result (wdquery-alist (getentities-uri qid l #:languages 
language))))
    (match result
((_ (entities (q id type (labels (result (value . val) lang) _ ...) _ ...)))
       val))))

scheme@(wikidata apis) [39]> (load "../guile-wikidata/wikidata/apis.scm")
scheme@(wikidata apis) [39]> (get-label "Q1111")
$25 = "electric charge"
scheme@(wikidata apis) [39]> (get-label "Q1111" #:language 'sv)
$26 = "elektrisk laddning"

--
Cheers Swedebugia



reply via email to

[Prev in Thread] Current Thread [Next in Thread]