Open heatherleaf opened 5 years ago
Please voice your opinions here! Just tagging some GF people, but everyone is of course welcome: @aarneranta @krangelov @Thomas-H @johnjcamilleri @inariksit @odanoburu
Thinking a bit more, and came to the following modification to (2):
2b. Keep intensional semantics, but disallow variants{}
completely. Further: let the semantics of nonExist
be extensional (as in (1)).
This will make it clearer that nonExist
is a different beast from variants
.
I don't have too much to add, but I think it is probably desirable that nonExist
is not interchangeable with variants{}
and that they mean distinct things. Making such a change will probably break some existing grammars, but if it's for the better then I'm for it.
Peter,
Thanks for your summary: you are certainly the world expert on the semantics of variants 😊
And I just have one strong opinion, which is: backward compatibility. This commits us to avoid changes that would break anyone's code.
The only reason ever to do this is if we find a bug that needs to be fixed. We have not promised to be bug-to-bug compatible. But even this requires thought, because it is not always clear what is a bug and what is, or has become, a feature.
So my definite vote is to keep the current behaviour of variants, |, and nonExist, as it is now and has been for many years.
This said, I am not always happy with what variants produce, and would like GF to provide alternatives, but with a different syntax so that old code retains its old semantics.
I have previously suggested something that is analogous to nonExist on the Str level, namely alternatives that are not multiplied across tables but stay on the leaves. My experiment with faking it using the pre construction showed that it would be possible without too much work (since it is the same kind of beast as pre but much simpler). And it would be very useful.
Aarne.
From: Peter Ljunglöf notifications@github.com Sent: Friday, March 8, 2019 5:02:33 PM To: GrammaticalFramework/gf-core Cc: Aarne Ranta; Mention Subject: Re: [GrammaticalFramework/gf-core] The semantics of empty disjunction (variants{}) (#37)
Thinking a bit more, and came to the following modification to (2):
2b. Keep intensional semantics, but disallow variants{} completely. Further: let the semantics of nonExist be extensional (as in (1)).
This will make it clearer that nonExist is a different beast from variants.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHubhttps://github.com/GrammaticalFramework/gf-core/issues/37#issuecomment-470979840, or mute the threadhttps://github.com/notifications/unsubscribe-auth/ACwYXYGUtUlu0Y6IXHa1ZYquvsUU2A6Iks5vUomZgaJpZM4bk6QY.
And I just have one strong opinion, which is: backward compatibility (...) So my definite vote is to keep the current behaviour of variants, |, and nonExist, as it is now and has been for many years
...which brings us back to my initial question: what is the semantics of variants{}
and nonExist
? I did a simple test, and they do not have the same semantics, in fact their current semantics is rather strange:
abstract TestAbs = {
cat S; A;
fun s1, s2 : A -> S;
a1, a2 : A;
}
concrete Test of TestAbs = open Prelude in {
lincat S = {s : Str};
A = {s1, s2 : Str};
lin s1 x = {s = x.s1};
s2 x = {s = x.s2};
a1 = {s1 = "a1"; s2 = variants{}};
a2 = {s1 = nonExist; s2 = "a2"};
}
Generating trees:
TestAbs> gt
s1 a2
s2 a2
Interesting! Note that a1
is not even generated, which is a bit strange since gt
is supposed to work only on the abstract syntax level. (In fact, if I only import the abstract syntax, then a1
is generated...)
@krangelov is this something you implemented on prupose, or is it just a consequence of something else?
Linearisation:
TestAbs> l s1 a1
[a1]
TestAbs> l s1 a2
TestAbs> l s2 a1
[a1]
TestAbs> l s2 a2
a2
hmm... what does this mean? Let's try this instead:
TestAbs> l -table a1
TestAbs> l -table a2
s1 :
s2 : a2
Conclusion: it seems like the current semantics of nonExist
is the "extensional" one, and variants{}
is "intensional". Just as my suggestion (2) above. @krangelov can you confirm or reject this?
Just three more things:
I still think we should disallow variants{}
anywhere except on the top-level!. This is because the meaning of this:
lin a1 = {s1 = "a1"; s2 = variants{}}
is exactly the same as this:
lin a1 = variants{}
so there's no point in using variants{}
anywhere else than on the top-level. It only creates confusion because grammar-writers will believe that it means something else.
(if disallowing is not an option, then I strongly argue for deprecation)
Currently nonExist
can only be used as a Str
, but it shouldn't be difficult to make it possible to use in place of a record or a table. Semantically, the meaning is just this:
nonExist : {s1,...,sn : X} ==> {s1 = nonExist; ...; sn = nonExist}
nonExist : (P => X) ==> table{P1 => nonExist; ...; Pn => nonExist}
The meaning of nonExist
and variants{}
must be documented!
The meaning of nonExist is documented here:
http://www.aclweb.org/anthology/W15-3305
I think it is also included in the reference manual and it is definitely different from variants {}. I agree that empty variants are only useful on the top level, where they serve as a placeholder to indicate that there is a missing linearization but you don't want to see warnings from the compiler. For backwards compatibility, however, it is better not to restrict the use of empty variants in other places.
It would be better to keep the current semantics of variants except that sometimes variants are expanded too eagerly. If I remember correctly:
let x = a | b in x ++ x
results in {aa, ab, ba, bb} while I would expect only {aa,bb}. Fixing this issue is not easy but would resolve many combinatoric explosions. Currently the way out is to define:
oper dup : Str -> Str = \x -> x++x;
and then to use dup (a | b). There are many other similar examples.
On Mon, 11 Mar 2019 at 15:50, Peter Ljunglöf notifications@github.com wrote:
Just three more things:
1.
I still think we should disallow variants{} anywhere except on the top-level!. This is because the meaning of this:
lin a1 = {s1 = "a1"; s2 = variants{}}
is exactly the same as this:
lin a1 = variants{}
so there's no point in using variants{} anywhere else than on the top-level. It only creates confusion because grammar-writers will believe that it means something else.
(if disallowing is not an option, then I strongly argue for deprecation) 2.
Currently nonExist can only be used as a Str, but it shouldn't be difficult to make it possible to use in place of a record or a table. Semantically, the meaning is just this:
nonExist : {s1,...,sn : X} ==> {s1 = nonExist; ...; sn = nonExist} nonExist : (P => X) ==> table{P1 => nonExist; ...; Pn => nonExist}
3.
The meaning of nonExist and variants{} must be documented!
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/GrammaticalFramework/gf-core/issues/37#issuecomment-471570818, or mute the thread https://github.com/notifications/unsubscribe-auth/ATBZZOcAELFThZL3a_tfeOWKsaUTfWlBks5vVm06gaJpZM4bk6QY .
Thanks for the clarification, I didn't know about that paper!
For backwards compatibility, however, it is better not to restrict the use of empty variants in other places.
But the compiler can give a warning when there's variants{}
in any other place.
It would be better to keep the current semantics of variants except that sometimes variants are expanded too eagerly. If I remember correctly:
let x = a | b in x ++ x
results in{aa, ab, ba, bb}
while I would expect only{aa,bb}
. Fixing this issue is not easy but would resolve many combinatoric explosions. Currently the way out is to define:oper dup : Str -> Str = \x -> x++x
; and then to usedup (a | b)
.
I tested and you're correct. I would say that's a bug - the first behavior is what I call "extensional disjunction" in my thesis, and GF otherwise uses intensional disjunction.
There are many other similar examples.
Such as the one in issue #14 ?
On Mon, 18 Mar 2019 at 15:03, Peter Ljunglöf notifications@github.com wrote:
But the compiler can give a warning when there's variants{} in any other place.
Sure that would make sense.
There are many other similar examples.
Such as?
oper foo : Bool => Str = \x => ("a"|"b") ++ bar x
would generate:
oper foo : Bool => Str = variants {table {True => "a"++bar True; False => "a"++bar False}; table {True => "a"++bar True; False => "b"++bar False}; table {True => "b"++bar True; False => "a"++bar False}; table {True => "b"++bar True; False => "b"++bar False}};
instead of:
oper foo : Bool => Str = variants {table {True => "a"++bar True; False => "a"++bar False}; table {True => "b"++bar True; False => "b"++bar False}};
On top of that you could add some records and other tables to make the example more and more complicated.
@aarneranta @krangelov What is the current semantics of
Prelude.nonExist
orvariants{}
? Is it intensional or extensional? (see issue #36 for more details)if it is intensional (like the current semantics of
variants{...}
), then it's only useful at the top-level of a linearisation definition:if it is extensional, then you can use it to state that some inflection forms do not exist:
(in the intensional semantics, this is equivalent to the previous definition)
I think that both
nonExist
andvariants{}
use intensional semantics, but please correct me if I'm wrong. In that case, it's a problem because people will think thatnonExist
is more useful than it really is.Here are some suggestions on alternative semantics for the two:
Let
nonExist
=variants{}
, and use the extensional semantics. This can be implemented by lettingnonExist
refer to a non-existing token which can never occur (such as&#!$
or something similar).nonExist
andvariants{}
become useful.variants{}
will have different semantics thanvariants{a;b}
.Let
nonExist
andvariants{}
denote different semantics (extensional resp. intensional).nonExist
is useful andvariants{}
andvariants{...}
will have the same semantics.nonExist
andvariants{}
are not interchangeable.Let
nonExist
=variants{}
, and keep using the intensional semantics.nonExists
andvariants{...}
will have the same semantics.Personally I prefer solution (1), but can live with solution (2). I really don't like solution (3).
If we choose the intensional semantics, I propose we only allow the use of
variants{}
at the top level of a linearisation. I.e., GF should allow this:but not this: