Fork me on GitHub
#meander
<
2021-02-22
>
zalky16:02:44

Hi all, just reading through the meander docs, and wondering if anyone could shed light on what the difference is between the scan and [ ...] formulations? For example:

{:user
 {:name ?name
  :favorite-foods (m/scan {:name ?food})}}

{:user
 {:name ?name
  :favorite-foods [{:name !food} ...]}}

noprompt16:02:53

(m/scan p1 ,,, pn) is similar to

[_ ... p1 ,,, pn & _]
or
(_ ... p1 ,,, pn & _)
but operates on seqable? things in general.

Jimmy Miller19:02:29

To explain the difference a bit more concretely, scan lets there be gaps in the data, where as ... requires all elements to make the pattern. You can see that in the difference between these two.

(m/search [1 2 3 4 5 6]
  (m/scan (m/pred even? ?xs))
  ?xs)

;; => [2 4 6]

(m/find [1 2 3 4 5 6]
  [(m/pred even? !xs) ...]
  !xs)

;; => nil

Carlo18:02:08

(m/match #{{:id 1} {:id 2}} #{{:id 1}} :yes)
works, but:
(m/match #{{:id 1} {:id 2}} #{{:id ?id}} :yes)
says that Set patterns may not contain variables . Does that mean that I can't check that a pattern is a subset of my data if it has logical variables, or is there a better way of expressing something like this?

Jimmy Miller18:02:58

Match requires things to be unambigious. But that isn’t the case here. So you can use m/search to get all the answers, or m/find to get the first.

(m/search #{{:id 1} {:id 2}} 
  #{{:id ?id}}
  [?id :yes])

;; =>
([2 :yes] [1 :yes])

Carlo19:02:42

thanks for the answer @U5K8NTHEZ, that's exactly what I needed! Amazing library!

🙂 3
Carlo22:02:32

I'm observing a weird behaviour that I think could be a bug. I'm in a cljs file: if I do

(m/search example-2 a-pattern an-action)
where example-2 is an actual binding in my file, all is good. But if I try to import the same binding from another file, writing:
(m/search workspace/example-2 a-pattern an-action)
then i get a spec error:
Syntax error macroexpanding cljs.core/fn.
Call to cljs.core/fn did not conform to spec.
-- Spec failed --------------------

  ([workspace/example-2_T__] ...)
    ^^^^^^^^^^^^^^^^^^^^^^^

has extra input

or

should satisfy

  vector?

-- Relevant specs -------

:shadow.cljs.devtools.cljs-specs/param-list:
  (clojure.spec.alpha/and
   clojure.core/vector?
   (clojure.spec.alpha/cat
    :params
    (clojure.spec.alpha/* :shadow.cljs.devtools.cljs-specs/binding-form)
    :var-params
    (clojure.spec.alpha/?
     (clojure.spec.alpha/cat
      :ampersand
      #{'&}
      :var-form
      :shadow.cljs.devtools.cljs-specs/binding-form))))
:shadow.cljs.devtools.cljs-specs/params+body:
  (clojure.spec.alpha/cat
   :params
   :shadow.cljs.devtools.cljs-specs/param-list
   :body
   (clojure.spec.alpha/alt
    :prepost+body
    (clojure.spec.alpha/cat
     :prepost
     clojure.core/map?
     :body
     (clojure.spec.alpha/+ clojure.core/any?))
    :body
    (clojure.spec.alpha/* clojure.core/any?)))

Jimmy Miller22:02:43

Sounds like a bug. If you let bins workspace/example-2 to a local variable does it work? Can't look at this right now. But will try to recreate tonight.

Carlo22:02:24

yes, either a variable in the same file or a variable in a let binding works:

(let [example-2 ...]
  (m/search example-2 a-pattern an-action))
Thank you!

Jimmy Miller22:02:04

Cool should be an easy fix.

🙌 3
Carlo22:02:23

and of course this works too:

(let [example-2 workspace/example-2] ...)

Carlo00:02:30

When you come back to this (no pressure), I'd like to understand better what's happening. Here are the macro expansions:

(let*
 [R__59579
  (clojure.core/case
   workspace/example-2
   (:a-pattern)
   (clojure.core/list :an-action)
   meander.match.runtime.epsilon/FAIL)]
 (if (meander.match.runtime.epsilon/fail? R__59579) nil R__59579)) 

(let*
 [R__59582
  (clojure.core/case
   example-2
   (:a-pattern)
   (clojure.core/list :an-action)
   meander.match.runtime.epsilon/FAIL)]
 (if (meander.match.runtime.epsilon/fail? R__59582) nil R__59582))
it seems to me that both of them should work :thinking_face:

Jimmy Miller02:02:56

So haven't had a chance to look into it. But judging from the first error, if you pass us a symbol as the first arg, we consider that the "target". Then as a way to make debugging easier, we often use the target name to derive new variables (using gensym or some other safe way). In this case, it looks like we did that in some local function, but since the symbol is not a simple symbol, that broke in the function definition. I don't see that in your macroexpansion. But definitely see it in the spec error you sent.

Jimmy Miller23:02:44

This has been fixed in the new release