Object name as variable in Logtalk - database

Is this possible to get the name of an object as a variable? I’m trying to make a database where each object represents each person. I’ve got objects with [name/1, surname/1], but when I ask e.g.
X::name(john).
it gives me an error. Ofc there is no problem to get the atom by using this method:
object_id::name(X).

The ::/2 message sending control construct indeed requires a bound first argument at call time. But you can enumerate existing objects using the current_object/1 built-in predicate:
| ?- current_object(Person), Person::name(john).
...
However, this solution may also result in errors as we will be enumerating all objects by backtracking and not all of them will understand a name/1 message. A better solution is thus to only enumerate objects that understand the name/1 message. Assuming that all objects representing a person implement (directly or through inheritance) a person_protocol, we can use the conforms_to_protocol/2 built-in predicate:
| ?- conforms_to_protocol(Person, person_protocol),
Person::name(john).
...
See https://logtalk.org/manuals/refman/predicates/conforms_to_protocol_2_3.html for details.

Related

Rust - Can I make this diesel dsl::find() function more generic?

I have a function that uses diesel to get an object from a DB based off the given ID:
fn get_db_site(pool: web::Data<Pool>, site_id: u32) -> Result<Site, diesel::result::Error> {
let conn = pool.get().unwrap();
dsl::site.find(site_id).get_result::<Site>(&conn)
}
This function is going to be exactly the same for every table I want to run it on so I'm hoping to put it in it's own utils file so I don't have to type the same thing in every time. The only problem is in order to call that find I need to do
crate::schema::site::dsl::site.find and I'm not sure how I can make that call generic to take any type. I know there are type arguments but I don't think that would work here
I normally advise against making diesel things more generic as this leads to really complex trait bounds quite fast. You normally never want to do this in application code. (It's a different thing for libraries that need to be generic). I normally compare the situation with plain SQL. For example if someone complains that users::table.find(pk) feels like duplication, ask yourself the following question: Would you feel that SELECT … FROM users is duplicated in the corresponding query SELECT … FROM users WHERE id = $. (The diesel dsl statement is basically the same).
So to answer your actual question, the generic functions needs to look something like this:
(Not sure if I got all bounds right without testing)
fn get_db_thing<T, U, PK>(pool: web::Data<Pool>, primary_key: PK) -> Result<U, diesel::result::Error>
where T: Table + HasTable<Table = T>,
T: FindDsl<PK>,
U: Queryable<SqlTypeOf<Find<T, PK>>, Pg>
{
let conn = pool.get().unwrap();
T::table().find(primary_key).get_result::<U>(&conn)
}
As you can see the list of trait bounds is already much longer than just having the load inline in the corresponding functions. In addition all the details added while constructing the query would now be required as generic function argument. At least the type for T cannot be inferred by the compiler, so from a code size point of view this solution is not "simpler" than just not making it generic.

Shared pointer in rust arrays

I have two arrays:
struct Data {
all_objects: Vec<Rc<dyn Drawable>>;
selected_objects: Vec<Rc<dyn Drawable>>;
}
selected_objects is guarenteed to be a subset of all_objects. I want to be able to somehow be able to add or remove mutable references to selected objects.
I can add the objects easily enough to selected_objects:
Rc::get_mut(selected_object).unwrap().select(true);
self.selected_objects.push(selected_object.clone());
However, if I later try:
for obj in self.selected_objects.iter_mut() {
Rc::get_mut(obj).unwrap().select(false);
}
This gives a runtime error, which matches the documentation for get_mut: "Returns None otherwise, because it is not safe to mutate a shared value."
However, I really want to be able to access and call arbitrary methods on both arrays, so I can efficiently perform operations on the selection, while also being able to still perform operations for all objects.
It seems Rc does not support this, it seems RefMut is missing a Clone() that alows me to put it into multiple arrays, plus not actually supporting dyn types. Box is also missing a Clone(). So my question is, how do you store writable pointers in multiple arrays? Is there another type of smart pointer for this purpose? Do I need to nest them? Is there some other data structure more suitable? Is there a way to give up the writable reference?
Ok, it took me a bit of trial and error, but I have a ugly solution:
struct Data {
all_objects: Vec<Rc<RefCell<dyn Drawable>>>;
selected_objects: Vec<Rc<RefCell<dyn Drawable>>>;
}
The Rc allows you to store multiple references to an object. RefCell makes these references mutable. Now the only thing I have to do is call .borrow() every time I use a object.
While this seems to work and be reasonably versitle, I'm still open for cleaner solutions.

Saving a decision tree model for later application in Julia

I have trained a pruned decision tree model in Julia using the DecisionTree module. I now want to save this model for use on other data sets later.
I have tried converting the model to a data array for export using writetable() and I have tried exporting using writedlm() and neither of these work. When I look at the type of the model I see that it is a DecisionTree.Node type. I don't know how to work with this and can't get it to export/save.
In:DataFrame(PrunedModel)
Out:LoadError: MethodError: `convert` has no method matching convert(::Type{DataFrames.DataFrame}, ::DecisionTree.Node)
This may have arisen from a call to the constructor DataFrames.DataFrame(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert(::Type{DataFrames.DataFrame}, !Matched::Array{T,2})
convert(::Type{DataFrames.DataFrame}, !Matched::Dict{K,V})
...
while loading In[22], in expression starting on line 1
in call at essentials.jl:56
In:typeof(PrunedModel)
Out:DecisionTree.Node
Any ideas how I can get this model saved for use later?
If I understand correctly that this is a Julia object, you should try using the JLD.jl package to save the object to disk and load it back in, preserving the type information.

D: Creating an array of templated objects

I'm trying to create an array of Regex objects, like so: Regex[] regexes;.
The compilation fails with main.d(46): Error: template std.regex.Regex(Char) is used as a type.
I find the documentation cryptic. All I understand is that templates generate code on compilation, but I don't see what's preventing me from creating an array of Regex.
There's an existing question on StackOverflow with the same problem, but it deals with C++, not D.
You cannot create a regex object without first instantiating the template with a type. this is because the actual type is generated at compile time based on the instantiation type you give. Regex itself is not an actual type, it is just a template function allowing you to generate a type when instantiated.
In this case you probably want to change:
Regex[] regexes;
into:
Regex!char[] regexes;
to tell the compiler that your regex contains chars as opposed to some derived type. This means specifically you are instantiating the Regex template with the type char.

Declaring tables in Slick

I've been getting errors when trying to do many-to-many relations in Slick. This test shows how to do many-to-many relations in Slick. I followed it but then go this error:
Select(TableNode, "id") found. This is typically caused by an attempt to use a "raw" table object directly in a query without introducing it through a generator
I then found out that this is caused by declaring your tables at a static location (an object) and then trying to import it (it works fine if the object is in the same block). http://slick.typesafe.com/doc/1.0.0/lifted-embedding.html#tables
Ok, so val T = new Table inside of an object is the answer. But now I'm getting this error:
recursive method bs needs result type
It doesn't need a result type if it is an object and not a val. I've heard of using a class but I can't find any examples on how to do this.
How do you declare many-to-many models and import them from somewhere else?
EDIT:
Here's a gist showing what I mean: https://gist.github.com/pjrt/5332311
If you run the first test, it will pass, no issue.
If you run the second test, the following error is thrown:
scala.slick.SlickException: Select(TableNode, "id") found. This is typically caused by an attempt to use a "raw" table object directly in a query without introducing it through a generator.
If you run the third test (using vals inside of objects instead of objects directly), you get this error:
recursive method bs needs result type
[error] val A = new Table[(Int, String)]("a") {
recursive value AToB needs type
[error] def as = AToB.filter(_.bId === id).flatMap(_.aFK)
I know why the errors are happening, but I want to know how people got around them. One way is to put the objects inside of a class and instantiating a class every time you want to use Slick (but this seems...weird). Another is to never use Slick-related stuff outside of the package (or at least many-to-many stuff) but that also seems bad.
My question, still is, how do you guys get around this? Is there a proper way?
The error message you showed makes me think that you defined your tables but tried to access them directly instead of using a for comprehension.
The test file you were referring has an example right at the bottom, after defining the many-to-many tables that goes like
val q1 = for {
a <- A if a.id >= 2
b <- a.bs
} yield (a.s, b.s)
q1.foreach(x => println(" "+x))
assertEquals(Set(("b","y"), ("b","z")), q1.list.toSet)
What you see is that object table A is used as a comprehension generator (i.e. a <- A)
Does your code access the tables in some other way?

Resources