Closed evan0greenup closed 6 months ago
Hi @evan0greenup.
Clorm does actually allow for this syntax. So the following should work as you expect:
from clorm import Predicate, ConstantStr
class Account(Predicate):
id: str
person: ConstantStr
balance: int
ConstantStr
is a subclass of str
and corresponds to clingo/logic-programming constants while str
corresponds to strings. So, the python code Account("x", "y", 3)
should map to the logic programming fact account("x", y, 3)
.
Also if you want the predicate to have a name that is not the default one you can use the following more convenient syntax:
class Account(Predicate, name="my_account"):
id: str
person: ConstantStr
balance: int
So, the above example will be my_account("x", y, 3)
. Finally, you can also reference an existing predicate sub-class to form more complex definitions:
class A(Predicate):
foo: int
bar: str
class B(Predicate):
blah: int
blob: A
which will match facts like b(1, a(3,"x")).
There are some things that I want to clean up before updating the documentation. The main limitation that I need to fix is that currently this type annotation syntax doesn't work when you have from __future__ import annotations
at the start of the file. I had a brief look to try to understand how pydantic implements it but unfortunately I couldn't find what I wanted; pydantic is a larger more complex code base so I need to spend more time to try to understand how it is implemented.
But apart from that the type annotation syntax works well and that is what I've been using for sometime.
@daveraja
I had a brief look to try to understand how pydantic implements it but unfortunately I couldn't find what I wanted; pydantic is a larger more complex code base so I need to spend more time to try to understand how it is implemented.
Why don't you use decorator to define predicate, similar to dataclasses.dataclass
in Python standard library. For example:
@clorm.as_predicate
class A:
foo: int
bar: str
If you want some extra argument for the predicate, like change default name
@clorm.as_predicate(name="my_a")
class A:
foo: int
bar: str
clorm.as_predicate
is equal to clorm.as_predicate()
like how dataclasses.dataclass
do.
And you can provide extra function like clorm.is_predicate
to replace what isinstance(obj, clorm.Predicate)
do previosuly.
Please have a look on https://raw.githubusercontent.com/python/cpython/main/Lib/dataclasses.py and get some heuristics.
Why don't you use decorator to define predicate, similar to dataclasses.dataclass in Python standard library. For example:
Yes, this certainly could be added as an optional syntax and would be more dataclass-like. But to be honest I don't see a particular advantage of one over the other, so it would be low on my list of priorities.
Please have a look on https://raw.githubusercontent.com/python/cpython/main/Lib/dataclasses.py and get some heuristics.
Can you please provide details as I'm not sure what you mean by "heuristics" in this context?
Can you please provide details as I'm not sure what you mean by "heuristics" in this context?
You previously said that pydantic
is large project and difficult to understand. I think dataclasses
is relatively small codebase which is much easier to understand.
Can you please provide details as I'm not sure what you mean by "heuristics" in this context?
You previously said that
pydantic
is large project and difficult to understand. I thinkdataclasses
is relatively small codebase which is much easier to understand.
Ok. Thanks.
With the release 1.5.0 the Pydantic style of type annotations for specifying Predicate sub-classes has now become the preferred mechanism and the documentation has been updated.
Closing this issue.
@daveraja ,
Does the error when from __future__ import annotations
be resolved?
@evan0greenup Yes. This is fixed with v1.5.0. There is a remaining bug that it doesn't work for inner predicate classes. But this is already fixed in the master branch and I will release it as v1.5.1 early next week. If you find any other cases where it doesn't work please open an issue.
Currently, to define a predicate
account/3
:For modern Python IDE or Lint checker,
Account.id
or<instance of Account>.id
has typetype
. All the operation related to this member will cause static analysis error.However, for
pydantic
ordataclasses
module. They define a structural object via "type-hint". (<details https://docs.pydantic.dev/latest/concepts/models/> and https://docs.python.org/3/library/dataclasses.html).This is very concise and efficient. All type checker and autocomplete system work properly.
It would be a good idea to follow the architecture and design pattern as
pydantic
. For example:For
id
andbalance
field, the base classclorm.Predicate
do conversion automatically. when accessing the member, it do conversion back also in automatic manner.This would be better to everyone.
@daveraja , @florianfischer91 , what are your opinions?