Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for every expression #8

Open
Gozala opened this issue Feb 26, 2024 · 4 comments
Open

support for every expression #8

Gozala opened this issue Feb 26, 2024 · 4 comments

Comments

@Gozala
Copy link

Gozala commented Feb 26, 2024

We have bunch of threads discussing this and loose consensus that we could leave this out in 1.0 as long as we can validate it can be added in the future.

Similar to #7 I'm leaning towards something along these lines

input

{
  "mail": [
    { "to": ["alice@web.mail", "malory@web.mail"], "content": "hello alice" },
    { "to": ["bob@gmail.com", "alice@web.mail" ], "content": "hi bob" }
  ]
}

policy

Every message in mail must have some recipient matching *.@web.mail.

[
  [".mail", "?", "?mail"],
  ["for", "?message", "?mail"],
  [".to", "?message", "?to"],
  ["in", "?email", "?to"],
  ["like", "?email", "*@web.mail"]
]
@Gozala
Copy link
Author

Gozala commented Feb 26, 2024

On the other hand if we embrace selector syntax from jq in #7 perhaps we could do the same for every in fact jq does have construction syntax which may be utilized

image

Perhaps above policy could be rewritten as follows

[
  ["[.mail]", "?", "?message"], // <-- every message under mail
  [".to[]", "?message", "?email"], // <-- some email from every message
  ["like", "?email", "*@web.mail"] // <-- must match the pattern
]

@Gozala Gozala changed the title support for every expression support for every expression Feb 26, 2024
@Gozala
Copy link
Author

Gozala commented Feb 26, 2024

Inlining some relevant comments from other thread

Just stashing some research here: this paper adds universal quantification to Kanren: https://www.cs.toronto.edu/~lczhang/jin_universal2021.pdf

It adds a form (forall (v) domain goal)

Translated to our format it looks roughly like this:

{ 
 policy: [ 
   ["forall", ["?goal"], [".foo.bar.[]", "$", "?domain"], 
     ["match", "?goal", "*@example.com"]
   ]
 ]
}


// Rearranged
{ 
  policy: [ 
    [".foo.bar.[]", "$", "?domain"],
    ["forall", ["?x"], "?domain", 
      ["match", "?x", "*@example.com"]
    ]
  ]
}

// Flattened

{ 
  policy: [ 
    [".foo.bar.[]", "$", "?domain"],
    ["forall", ["?x"], "?domain"],
    ["match", "?x", "*@example.com"]
  ]
}

...which looks a heck of a lot like my every suggestion from earlier.

What I like about this is we could add this to the version with an implied some without having to rework the version that doesn't have it 👍

@expede
Copy link
Member

expede commented Feb 27, 2024

On the other hand if we embrace selector syntax from jq in #7

I think we've now done that: universal quantification by default ✅

@Gozala
Copy link
Author

Gozala commented Mar 1, 2024

// data set
{
  foo: [
    {bar: [1, 0, 0]},
    {bar: [0, 1, 0]},
    {bar: [0, 0, 1]},
  ]
}

// Task: every `foo` has a `bar` that contains at least one >0 element.

// Explicit version is very confusing unless you give very descriptive variable
// names.
[
 ["every", ".foo[]", "?every-foo"]
 [".bar[]", "?every-foo", "?bar-of-every-foo"], // <- this is confusing what is the ?bar
 ["some", "?bar-of-every-foo", "?some-bar-of-every-foo"]
 [">", "?some-bar-of-every-foo", "0"]
]

// Implicit version is a lot shorter but not very intuitive at all, especially
// when second clause could contradict the first one yet be correct.
[
  [">", ".foo[].bar[]?", 0],
  ["<", ".foo[].bar[]?", 0]
]


// Attempt to articulate the problem I have with pushing some / every into the
// the selector is that it seems intuitive but it is misleading.

[">", ".foo[].bar[]?", 0]

// This to me reads as

jq(".foo[].bar?[]", args).some((bar) => bar > 0)

// That is because `jq` returns matches as collection and then you do something
// to it. That is incorrect however because what the policy is actually saying
// is

jq(".foo[]").every(foo => foo.some((bar) => bar > 0))

// It is possible to make a case for the ☝️ interpretation, if you do not have
// variables in the system, but if you introduce them things become even more
// confusing because if we assigned query to the variable it now contains a
// collection as opposed to function you can apply predicates to.
[
  [".", ".foo[].bar[]?", "?some-bar-of-foo"],
  [">", "?some-bar-of-foo", 0],
]

// In comparison this is a lot more clear to me.
[
  ["every", ".foo",
    ["some", ".bar[]" [">", ".", 0]]
]

// Datomic way is not intuitive, have to read few times to comprehend, but it
// is not misleading.
[
  // no foo that does not have a bar > 0
  ["not",
    [".", ".foo[]", "?foo"],
    ["not", [".bar[]", "?foo", "?bar"],
            [">", "?bar", 0]]
  ]
]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants