Prolog のプログラムを
ということをやりたいので、ChatGPT で調べました。
前回の代数的構造の後、まず以下のように入力しました。
- この代数的構造に従って Prolog の構文解析を行うプログラムを作ってください
- 項の構文解析を追加してください
- 代数的構造に対応するクラスを作ってそのクラスのオブジェクトに変換してください
- 構文解析のモジュールを使うように書き換えてください
- このプログラムを、代数的構造に対応するクラスに変換するように書き換えてください
- 代数的構造で Prolog の動作を説明してください
- 代数的構造のクラスに、 Prolog の動作の処理を追加してください
その後以下のように入力しました。
入力: C# に書き換えてください
結果:
using System; using System.Collections.Generic; using System.Linq; namespace PrologEngine { public class Term { public string Type { get; } public string Value { get; } public List<Term> Args { get; } public Term(string type, string value, List<Term> args = null) { Type = type; Value = value; Args = args ?? new List<Term>(); } public override string ToString() { if (Type == "compound") return $"{Value}({string.Join(", ", Args)})"; return Value; } public bool Unify(Term other, Dictionary<string, Term> bindings) { if (Type == "variable") { if (bindings.ContainsKey(Value)) { return bindings[Value].Unify(other, bindings); } bindings[Value] = other; return true; } if (other.Type == "variable") { return other.Unify(this, bindings); } if (Type != other.Type || Value != other.Value) return false; if (Args.Count != other.Args.Count) return false; for (int i = 0; i < Args.Count; i++) { if (!Args[i].Unify(other.Args[i], bindings)) return false; } return true; } public Term Substitute(Dictionary<string, Term> bindings) { if (Type == "variable" && bindings.ContainsKey(Value)) { return bindings[Value].Substitute(bindings); } if (Type == "compound") { var substitutedArgs = Args.Select(arg => arg.Substitute(bindings)).ToList(); return new Term(Type, Value, substitutedArgs); } return this; } } public class Literal { public string Predicate { get; } public List<Term> Terms { get; } public Literal(string predicate, List<Term> terms) { Predicate = predicate; Terms = terms; } public override string ToString() { return $"{Predicate}({string.Join(", ", Terms)})"; } public bool Unify(Literal other, Dictionary<string, Term> bindings) { if (Predicate != other.Predicate || Terms.Count != other.Terms.Count) return false; for (int i = 0; i < Terms.Count; i++) { if (!Terms[i].Unify(other.Terms[i], bindings)) return false; } return true; } public Literal Substitute(Dictionary<string, Term> bindings) { var substitutedTerms = Terms.Select(term => term.Substitute(bindings)).ToList(); return new Literal(Predicate, substitutedTerms); } } public class HornClause { public Literal Head { get; } public List<Literal> Body { get; } public HornClause(Literal head, List<Literal> body) { Head = head; Body = body; } public override string ToString() { if (Body.Count > 0) return $"{Head} :- {string.Join(", ", Body)}."; return $"{Head}."; } } public class PrologProgram { private List<HornClause> Clauses { get; } public PrologProgram() { Clauses = new List<HornClause>(); } public void AddClause(HornClause clause) { Clauses.Add(clause); } public IEnumerable<Dictionary<string, Term>> Query(Literal goal) { return Resolve(new List<Literal> { goal }, new Dictionary<string, Term>()); } private IEnumerable<Dictionary<string, Term>> Resolve(List<Literal> goals, Dictionary<string, Term> bindings) { if (!goals.Any()) { yield return bindings; yield break; } var currentGoal = goals.First(); var remainingGoals = goals.Skip(1).ToList(); foreach (var clause in Clauses) { var localBindings = new Dictionary<string, Term>(bindings); if (clause.Head.Unify(currentGoal, localBindings)) { var newGoals = clause.Body.Select(l => l.Substitute(localBindings)).ToList(); foreach (var result in Resolve(newGoals.Concat(remainingGoals).ToList(), localBindings)) { yield return result; } } } } } class Program { static void Main(string[] args) { // Define the Prolog program var program = new PrologProgram(); program.AddClause(new HornClause( new Literal("p", new List<Term> { new Term("variable", "X"), new Term("compound", "f", new List<Term> { new Term("constant", "a"), new Term("constant", "b") }) }), new List<Literal> { new Literal("q", new List<Term> { new Term("variable", "X") }), new Literal("r", new List<Term> { new Term("compound", "f", new List<Term> { new Term("constant", "a"), new Term("constant", "b") }) }) } )); program.AddClause(new HornClause( new Literal("q", new List<Term> { new Term("constant", "a") }), new List<Literal>() )); program.AddClause(new HornClause( new Literal("r", new List<Term> { new Term("compound", "f", new List<Term> { new Term("constant", "a"), new Term("constant", "b") }) }), new List<Literal>() )); // Query the program var goal = new Literal("p", new List<Term> { new Term("variable", "Y"), new Term("compound", "f", new List<Term> { new Term("constant", "a"), new Term("constant", "b") }) }); Console.WriteLine("Query: " + goal); var results = program.Query(goal); Console.WriteLine("Results:"); foreach (var result in results) { foreach (var binding in result) { Console.WriteLine($"{binding.Key} = {binding.Value}"); } } } } }
入力: Python の lark モジュールのグラマーの各要素を C# の(各代数的構造のクラスに変換する)関数定義に書き直すことによって Prolog の構文解析を C# に書き直してください
結果:
using System; using System.Collections.Generic; using System.Linq; namespace PrologParser { public class Term { public string Type { get; } public string Value { get; } public List<Term> Args { get; } public Term(string type, string value, List<Term> args = null) { Type = type; Value = value; Args = args ?? new List<Term>(); } public override string ToString() { if (Type == "compound") return $"{Value}({string.Join(", ", Args)})"; return Value; } } public class Literal { public string Predicate { get; } public List<Term> Terms { get; } public Literal(string predicate, List<Term> terms) { Predicate = predicate; Terms = terms; } public override string ToString() { return $"{Predicate}({string.Join(", ", Terms)})"; } } public class HornClause { public Literal Head { get; } public List<Literal> Body { get; } public HornClause(Literal head, List<Literal> body) { Head = head; Body = body ?? new List<Literal>(); } public override string ToString() { if (Body.Count > 0) return $"{Head} :- {string.Join(", ", Body)}."; return $"{Head}."; } } public static class PrologParser { public static Term ParseTerm(string input) { input = input.Trim(); if (char.IsUpper(input[0])) { // Variable return new Term("variable", input); } else if (input.Contains('(')) { // Compound term var name = input.Substring(0, input.IndexOf('(')); var argsString = input.Substring(input.IndexOf('(') + 1, input.Length - input.IndexOf('(') - 2); var args = ParseArguments(argsString); return new Term("compound", name, args); } else { // Constant return new Term("constant", input); } } public static List<Term> ParseArguments(string input) { var args = new List<Term>(); var stack = new Stack<char>(); var current = ""; foreach (var ch in input) { if (ch == ',' && stack.Count == 0) { args.Add(ParseTerm(current)); current = ""; } else { if (ch == '(') stack.Push(ch); if (ch == ')') stack.Pop(); current += ch; } } if (!string.IsNullOrWhiteSpace(current)) { args.Add(ParseTerm(current)); } return args; } public static Literal ParseLiteral(string input) { var predicate = input.Substring(0, input.IndexOf('(')); var argsString = input.Substring(input.IndexOf('(') + 1, input.Length - input.IndexOf('(') - 2); var terms = ParseArguments(argsString); return new Literal(predicate, terms); } public static HornClause ParseClause(string input) { var parts = input.Split(new[] { ":-" }, StringSplitOptions.None).Select(p => p.Trim()).ToArray(); var head = ParseLiteral(parts[0]); if (parts.Length > 1) { var bodyLiterals = parts[1].Split(',').Select(ParseLiteral).ToList(); return new HornClause(head, bodyLiterals); } return new HornClause(head, new List<Literal>()); } public static List<HornClause> ParseProgram(string input) { var clauses = new List<HornClause>(); var lines = input.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { clauses.Add(ParseClause(line.Trim())); } return clauses; } } class Program { static void Main(string[] args) { // Example Prolog program as a string string prologProgram = @" p(X, f(a, b)) :- q(X), r(f(a, b)). q(a). r(f(a, b)). "; // Parse the program var clauses = PrologParser.ParseProgram(prologProgram); // Print parsed clauses foreach (var clause in clauses) { Console.WriteLine(clause); } } } }
プログラムを書いてもらうことはできたので、これを修正していきます。

