meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
Lucy Wang 2020-09-25T10:16:00.138200Z

how meander is better than specter when restructuring data https://github.com/redplanetlabs/specter/issues/277#issuecomment-698847230

🙂 1
unbalanced 2020-09-25T14:29:04.138900Z

I'm not sure if the manual version there is charitable...

Lucy Wang 2020-09-25T14:32:01.139400Z

by charitable you mean ..?

unbalanced 2020-09-25T14:36:28.140200Z

Well I mean without any sort of let or letfn I would think something like this would make a little more sense:

(transduce
 (map (juxt :id #(select-keys % [:pick-me/b :pick-me/c])))
 (completing
  (fn [res [id m]]
    (assoc res id (into {} (map (fn [[k v]] [(-> k name keyword ) v])) (seq m)))))
 {}
 data)

Lucy Wang 2020-09-25T14:40:45.141400Z

there may be others like pick-me/d in addition to pick-me/b and pick-me/c , so you can not assume there are only these two such keys

Lucy Wang 2020-09-25T14:41:56.142300Z

but the point is not how to best implement the handwritten version, but that no hand written version could be as expressive as using meander

unbalanced 2020-09-25T14:42:31.143Z

Oh for sure. But if you want to make a strong point, you need to pick the strongest possible counterargument

unbalanced 2020-09-25T14:44:27.144400Z

No doubt the meander is more elegant. But I would just fear that someone might think the example was constructed to make vanilla clojure seem more inelegant than it is (Edit: I'm an idiot, disregard)

❌ 1
Lucy Wang 2020-09-25T14:45:32.145Z

tbh the hand-crafted code is almost the best version I could write ..

unbalanced 2020-09-25T14:47:35.145400Z

😬 I'm sorry, I'm an asshole, I didn't realize you wrote that

Lucy Wang 2020-09-25T14:48:14.146200Z

nvm 😄

unbalanced 2020-09-25T14:48:19.146300Z

Well I can't use specter at all so maybe I was just trying to make myself feel better, I didn't mean for it to come across like that 🙏

😎 1
unbalanced 2020-09-25T14:50:22.146600Z

🙇

2020-09-25T15:57:21.147900Z

I'm trying to copy the functionality and syntax of metosin/malli using meander. However, I came across behavior that I don't understand. I probably don't know how macros work, but I can't figure it out myself; (

2020-09-25T15:58:45.148900Z

(require '[meander.epsilon :as r])
(require '[taoensso.encore :as e])

(r/defsyntax ->schema [schema]
  (r/match schema
    [:map . (r/cata !x) ...] (r/subst {& [!x ...]})
    [(r/or (r/pred keyword? ?k)
           (r/pred string? ?k))
     (r/cata ?v)] {?k ?v}

    ?f `(r/pred ~?f)))

(r/match {:a 1.0 :b 1.0}
  (->schema [:map [:a double?] [:b double?]]) true
  _                                           false)
;; => true

(def x [:map [:a double?] [:b double?]])

(e/caught-error-data
  (r/match {:a 1.0 :b 1.0}
    (->schema x)  true
    _             false))
;; => {:err-type  java.lang.IllegalArgumentException,
;;     :err-msg   "Key must be integer",
;;     :err-cause nil}

noprompt 2020-09-25T16:22:07.150Z

@wxitb2017 FYI there is m/keyword for pattern matching on keywords. 🙂

(m/rewrite data
  [{:id !id (m/keyword "pick-me" !k) (m/some !v)} ...]
  {& ([!id {!k !v}] ...)})

👍 3
jimmy 2020-09-25T16:36:11.150500Z

So I'm not sure how to solve this problem. I'm trying to play around with it. But what is happening is that the x there is actually just the symbol x. It isn't the value sliced in. That is what is causing the error. Trying to think about how you would do that, not really sure.

noprompt 2020-09-25T16:38:10.150700Z

The trouble here is that the value x in

(->schema x)
is not passed to the ->schema syntax extension function, the symbol x is. So what happens is that the extension expands to (x {:a 1.0 ,,,}) or
([:map [:a double?] [:b double?]] {:a 1.0 ,,,})
and thats why you get the error. If you want the extension to get the value you’ll need to use eval.

jimmy 2020-09-25T16:38:51.150900Z

(m/match {:a 1.0 :b 1.0}
  (->schema #'x)  true
  _             false)
Seems to work.

jimmy 2020-09-25T16:43:29.151200Z

You do have to add m/keyword around the !k to get the same output, just fyi.

(m/rewrite data
  [{:id !id (m/keyword "pick-me" !k) (m/some !v)} ...]
  {& ([!id {(m/keyword !k) !v}] ...)})

jimmy 2020-09-25T16:46:22.151500Z

Really love all the comparisons you are doing here. Thanks for doing this :)

2020-09-25T16:52:54.151700Z

@jimmy I don't know why, but it doesn't work for me. Exactly the same error.

2020-09-25T16:53:52.151900Z

@noprompt I don't know where to use eval, could you give an example? EDIT: Already found, it works, thanks! EDIT: ... and it's incredibly slow. It's a pity.

jimmy 2020-09-25T17:04:17.152300Z

Sorry, bad repl state

jimmy 2020-09-25T17:06:09.152500Z

What did you end up doing? What performance are you getting? What would you expect it to be?

2020-09-25T17:11:25.152700Z

Meander is amazing and I play without any purpose. I check how little code is needed to get functionality of other libraries.

2020-09-25T17:11:57.152900Z

When I say it's incredibly slow, I meant eval

jimmy 2020-09-25T17:15:43.153100Z

Glad to hear 🙂 Just always on the look out for potential performance issues. Once jit kicks in, I get the exact same performance of these two

(m/defsyntax ->schema [schema]
  (m/match (eval schema)
    [:map . (m/cata !x) ...] (m/subst {& [!x ...]})
    [(m/or (m/pred keyword? ?k)
           (m/pred string? ?k))
     (m/cata ?v)] {?k ?v}
    ?f `(m/pred ~?f)))

(def x [:map [:a double?] [:b double?]])

(defn validate-1 [data]
   (and (map? data)
        (double? (:a data))
        (double? (:b data))))

(defn validate-2 [data]
  (m/match {:a 1.0 :b 1.0}
    (->schema x)  true
    _             false))

2020-09-25T17:20:30.153600Z

So it seems that I used eval not in the right place. ; )

2020-09-25T17:45:45.153800Z

However, it seems that a more generic function cannot be done. An exception Can't eval locals is thrown.

2020-09-25T17:46:03.154Z

(r/defsyntax ->schema [schema]
  (r/match (eval schema)
    [:map . (r/cata !x) ...] (r/subst {& [!x ...]})
    [(r/or (r/pred keyword? ?k)
           (r/pred string? ?k))
     (r/cata ?v)] {?k ?v}
    ?f `(r/pred ~?f)))

(defn valid? [schema data]
  (r/match data
    (->schema schema) true
    _ false))

jimmy 2020-09-25T17:47:51.154200Z

Yeah. ->schema is being expanded at compile time. And schema isn't known at that point.

jimmy 2020-09-25T17:48:23.154400Z

We have plans for an interpreter that would allow more dynamic things. But obviously that would be slower.

2020-09-25T17:50:38.154600Z

It is still awesome