@dominicm Whatever you’re working on can I conveniently do something like
(m/rewrite form
(t/deftest _ & (m/gather (t/testing & _ :as !test-forms)))
(do . (t/deftest ~(gensym) !test-forms) ...))
I haven’t gotten around to it yet but I really wanna be able to do something like this from my editor.
Right now I have to do something like like (def form ,,,)
and then eval the rewrite rule in my buffer, copy/paste.
So, this shouldn't happen, right? https://gist.github.com/eraserhd/6869f014414ab605efeb4a47410ca214
Once this patch lands I will reason more about this. Right now that bug is throwing me off. But yes I think you are probably right that there will be a case of P ^ ~P. But that is because we are searching. We are trying to find some subset of the map that will satisfy both of theses predicates. So we can search in the hash and find a way of satisfying both. Maps don't do the repeat operator. The behavior you want is what we would have in a hash-map operator. It would do all the things you are talking about.
So yes, you can indeed get p and not p. And I do think that makes sense.
(let [prod-snapshot
{1 2
2 1
3 5
5 3}]
(m/search prod-snapshot
(m/and {_ ?p} (m/not {_ ?p}))
?p))
When we are searching on maps, we are searching for key value pair combinations that match our pattern. We are not saying that the whole map needs to meet our requirements. For example.
(let [prod-snapshot
{1 2
2 1
3 5
5 3}]
(m/search prod-snapshot
{?p ?q
?q ?p}
[?p ?q]))
;; =>
([5 3] [2 1] [1 2] [3 5])
In my view, this makes sense. Currently to get the behavior you are looking for you’d need to do something like this.
(let [prod-snapshot
{1 2
2 1
3 5
5 3}]
(m/search prod-snapshot
{?p _
& (m/seqable [_ (m/not ?p)] ...)}
?p))
This says that none of the elements have ?p in the value position. The difference here is really that some vs none. With (m/not {_ ?p})
you are saying is there any key value pair that has a value that is not ?p. We are not asserting anything about the whole entire map, just some part of it. We should add the hash-map operator to allow you to talk about the whole thing. I will try to find some time over the christmas break to do that and make sure tests are working properly.
On master the original problem is fixed, but it has uncovered more issues we have with negation that might take a bit more work to fix. Will hopefully find some time to file bug reports for those.I'm completely unable to model this. Can I ask some questions?
In (m/not {?k ?v})
, is ?k
supposed to be bound?
When searching.
2. The conclusion from above is that whether {?k ?v} matches some map is irrelevant as to whether (m/not {?k ?v})
matches the map?
(That's how we get (P and not P).
Sadly right now no. I'm not sure if we could always do that even if we did support it
That's on binding ?k?
Yes. Unless it is already bound. It won't be
But it should, you are saying?
I'm unsure. If we can do it yes. But it isn't currently supported.
Ok.
The code gen does not try to bind it.
Ok, that helps me understand this a little bit better.
So should (m/search [1 2] (m/not [_ ... 2 . _ ...]) :ok)
return (:ok)
?
Oh, better example:
should (m/search #{1 2} (m/not #{2}) :ok)
return (:ok)
.
Yes
If it doesn't, that has been fixed on master and we need to release a new version.
Back to the previous example with the ellipsis then... that should return (:ok)
?
I think I'm forming a kind of model here, maybe?
I'm grabbing lunch with a friend right now so I won't be able to respond right now. I'm also traveling this whole weekend. But once I get some free time I plan on looking into how not is working with search. Write a bunch of tests and see what things I feel are right and wrong.
Which example?
The (m/search [1 2] (m/not [_ ... 2 . _ ...]) :ok) ;=> (:ok)
Yes that should.
And does on master. But maps are different. If you want the semantic for maps you get for vectors use seqable.
OK, respond later, but I have another: (m/search [1 2] (m/not 6) :ok) ;=>
(:ok)`
Enjoy your lunch, tho.
That last one is correct.
In simple cases like this macroexpansion should tell you a decent amount. The tricky cases that we need to be more comprehensive about are sets and maps. They have different semantics than ordered collections and we need to think about those in the face of negation.
wrt "On master the original problem is fixed", I can't find those commits. Did you mean epsilon?
Yes. Sorry. I meant epsilon.
(m/search {:a 2, :b 1} (m/not {:a 2}) :ok) ;=> nil
is one of those uncovered issues?
I was trying to contrast the maven package and git. There are some unreleased fixes.
I'm not sure about that one. Sorry on my phone.
ah, ok. np
I can cut what’s current in a couple hours if you need @eraserhd
Was just trying to pack in a couple more patches before I did that. 😀
@noprompt it would be helpful for me to see the code to understand this m/search thing. I can't upgrade yet, as it will break a lot of my code.
I hope other people are not in that boat, and I don't want you to publish early because of me.
What code are you hoping to see @eraserhd? The problem with search that we did fix was around search and m/not
. Basically search was broken with not because if something failed to match instead of returning FAIL we were returning nil, but then checking if it equaled fail. That is why you were having the weird behavior where find would return something, but search would not.
That didn’t fix your example above. (m/search {:a 2, :b 1} (m/not {:a 2}) :ok)
.
What is happing here is that we are trying to do an optimization that makes not
break. In this case it is because {:a 2}
is a literal. I have a fix for that one. Waiting to hear back from Joel to see if he agrees with the change then should push it up.
Right now searching with not on maps seems to have many cases that are broken. That change should fix a good amount of them. But this is an area we need to have better test coverage on. I should have some time in the new two weeks to accomplish that.
I will do the same for sets and make sure they behave as expected.
I'm really sorry you've encountered this bugs :(
@eraserhd that search is working fine. {:a 2}
is a submap of the input.
The not
says it shouldn’t be.
Aren't we searching for a map that isn't a submap? Maybe I just don't understand search and not.
{:b 1} is a submap we can find by searching that map and it doesn't match the pattern.
@eraserhd I think I made a mistake regarding my earlier answer.
I’m on vacation with kids, so I’m erratic answering. Sorry about that... I’ll be back later.
No worries. We are still hashing all this stuff out. Trying to make sure we get the semantics of this right rather than just an ad-hoc solution.
I hadn't designed it for ad hoc stuff, but it would work for that if called correctly.
Hmm… yeah, it looks like the find
is wrong.
I’ll take a close look.
Oh wait, no, its not wrong. The find
does seem suspicious.
Hmm… gimme a bit.
@eraserhd I updated the gist.
Lemme know when you get something operational.