(seqable <pattern> ...)
is like [<pattern> …] but works for anything in clojure that is seqable. That means that everything in the collection must match that pattern.
(scan <pattern>)
actually expands to something like [_ ... <pattern> . _ ...]
. Scan is looking for anywhere in the collection that the pattern could exist. Scan actually allows you to try and match on multiple patterns. It will search through the collection finding all the elements that can match your pattern and ignore all the rest. Scan must be used with search
Finally (gather <pattern>)
says find me all the things in the collection that match this pattern and gather them up for me. Anything that doesn’t match I don’t care about it.
I should think about writing an article explaining these. None of them are actually primitive. They are things we have found useful and added to meander, but they are all just extensions built on top of the base.
This is helpful. Thanks. I noticed an Github issue to write a top-down tutorial. I think that would help me a lot. It's been a long time since term rewriting systems in school and I'm finding it hard to see the forest for the trees.
It's generally doing logic programming on a large map... I want to find all x such that y and z, with joins across the map. So yes.
Two possible solutions:
1. The naive parsing. If a variable which could be bound is mentioned in the body, make it bound first.
This would be wrong if we let-bind a variable name which is bound elsewhere.
2. Metadata on the function indicating what it needs (in other words, manual).
3. A new syntax, (m/app' f pat & args)
, where no variables are bound during compilation of f
, and f
is applied to the match value and the args (which could be already-bound) and matched to pat.
We could also try giving logic variables a priority.
@eraserhd I’m thinking about #3 a bit now. What do you think of this sketch?
(m/compute ?result + ?a ?b)
;; `?a` and `?b` must be bound
;; `?result` matches the result of the function application.
This is venturing near constraint territory.
(m/compute true < ?a ?b)
hmm.
This is pretty close to m/let.
m/let presumably has the same problems as m/app wrt captured variables?
I think m/compute is slightly awkward.
I wouldn't bat an eye if that's what I got.
(m/compute ?result (+ ?a ?b))
feels slighty better. In this example, only a list with simple subexpressions is allowed.
There's a form like this in Datomic. It's not clearly defined what is allowed in subexpressions in Datomic, and occasionally I can get away with something useful, but not much.
In Datomic, [(+ ?a ?b) ?result]
.
IIRC, [(+ ?a (+ 1 2)) ?result]
works, but [(+ ?a (+ 1 ?b)) ?result]
does not.
(variables have to be at the top)
And, I guess this is just let with a rule that any variables are at the top.
I think something like
(m/compute result-pattern fn-pattern arg-patterns ...)
might be have some useful properties because fn-pattern
can be bound to a fn from Clojure explicitly
(m/compute ?res ~+ ?a ?b)
Its not clear to me what extra round braces provide.
To be clear, I’m thinking of what the primitive form of this would be.
ah
Because I think m/app
would emerge from this easily.
(m/app inc ?res)
;; ==
(m/compute ?res ~inc)
Must all args, aside from f, be logic or memory variables?
But also, we could get constraints out of this too.
No.
(m/compute 2 ~+ 1 1) ;; matches
(m/compute 3 ~+ 1 1) ;; fails
Ok, then I like this.
And if you would like round braces, of course, you could syntax that on later.
right
1. wacky idea - it's possible to attach metadata to things such that + could be reversible - e.g. ?result bound, but an arg not. Although, I guess that's also not a primitive?
2. does "constraints" imply unification?
Maayybe.
hrmm. I can't think of a use for it. But I shall pay more attention.
There have been a few cases of people talking about patterns like
(m/and ,,, (m/guard (< 1 ?y)))
Regarding unification, I’ve been wanting to venture more into that territory because there’s a lot of power there and whole bunch of stuff falls out. Pattern matching is a special case of unification where one of the terms being unified is ground.
Back to 1. no that isn’t wacky but it would probably mean that we’d need to talk about domains.
Which, honestly, that’s going to have to happen anyway.
Because substitution currently does not have a failure semantic and it only computes a single result. We have an open ticket for generating values, this is essentially the search
version of subst
. A primary reason it hasn’t be started is that in order to do so a notion of failure is required.
hmm
that's kind of neat
I think so too. 🙂 Shapes are kind of trippy.
this reminds me of a completely different use case I have - testing. The problem here is that it needs much better error messages.
Totally!
btw, I read syntax.clj and some of ir.clj. Which, historically, predicts I'll contribute in a few weeks.
cljc :D
Its a bit of a mess in there. I’m sorry. I tried to keep it tidy while also trying to push out code for Clojurist Together.
I’ve started some work on the zeta
branch; the pace there will be much slower.
But epsilon
is going to be around for a while longer and it’d probably be a good idea to make an issue or two for some of the design problems therein.