Забавно, это то, о чем я беспокоюсь и в последнее время.У меня есть частичное решение, которое зависит от динамического хранилища и определения фактов, которые вы хотите получить случайным образом.Я не влюблен в это, потому что это зависит от динамического хранилища, а также потому, что это зависит от изготовления метаданных, которые могут быть не синхронизированы.Тем не менее, это может быть достаточно для ваших целей.Он также не полностью отражает ваш API, потому что вы должны предложить некоторую подсказку, какой «вид» факта вас интересует. На практике это, вероятно, сработает нормально, потому что вы вряд ли окажетесь вситуация, в которой любой факт может сработать, потому что он, вероятно, потерпит неудачу при следующем сопоставлении с образцом.
Моя основная хитрость заключается в том, чтобы использовать =..
для разборки предикатов и использовать asserta
дляприсвойте каждому факту значение индекса.Если вы хотите, чтобы это работало лучше, вам придется использовать некоторую директиву индексации, чтобы сказать Прологу, что вы хотите, чтобы она индексировалась полностью до третьего поля моего random_fact
, но я не зашел так далеко.Для небольших баз данных (не WordNet) это, вероятно, будет в порядке, но для более крупных вам, вероятно, понадобится производительность.
% random_fact(Head, Instantiation, Index)
:- dynamic(random_fact/3).
% fact_count(Head, Count)
:- dynamic(fact_count/2).
% one big side-effect to make it possible to query for a random predicate
prepare_randomization_metadata(Goal) :-
findall(Goal, Goal, Occurrances),
prepare_randomization_metadata(Occurrances, 0),
Goal =.. [Head|_],
length(Occurrances, N),
asserta(fact_count(Head, N)).
prepare_randomization_metadata([], _).
prepare_randomization_metadata([Goal|Goals], N) :-
Goal =.. [Head|_],
asserta(random_fact(Head, Goal, N)),
N1 is N+1,
prepare_randomization_metadata(Goals, N1), !.
Итак, как вы можете видеть, движок здесь в основном для достижения поставленной цели.и создать небольшую базу метаданных.Вероятно, это может быть улучшено кем-то, кто знает Пролог лучше меня.Чтобы использовать его, вы ведете его так:
?- prepare_randomization_metadata(upred(X, Y, Z)).
true.
Теперь у вас есть база данных с такими фактами:
random_fact(upred, upred(mary, have, knife), 0).
random_fact(upred, upred(john, have, sword), 1).
...
Это то, что вы можете аргументировать с помощью Пролога.Поэтому, если вам нужен второй предикат, вы можете запросить его следующим образом:
?- random_fact(upred, X, 1)
X = upred(mary, have, knife) ;
false.
Теперь get_random_pred
довольно просто, но нам нужен дополнительный аргумент для определения того «вида» факта, который нам нужен:
get_random_pred(Head, Pred) :-
fact_count(Head, N),
% pick a random number between 0 and the # of facts we have for this pred
random(0, N, I),
random_fact(Head, Pred, I), !.
Я еще недостаточно хорош с Прологом, чтобы сказать вам, почему иногда мне показалось, что у меня было несколько решений, но это было так, поэтому я вставил красный срез в конце.Но если вам нужно несколько решений, достаточно легко написать версию, которая тоже это делает.
endless_random_facts(Head, Fact) :- repeat, get_random_pred(Head, Fact).
Например:
?- get_random_pred(upred, X).
X = upred(sword, is, long) ;
X = upred(john, have, sword) ;
X = upred(mary, have, knife) ;
X = upred(john, have, sword) ;
X = upred(john, have, sword) ;
В любом случае, надеюсь, это поможет,несмотря на недостатки.Я тестировал только в SWI-Prolog.