Created
February 23, 2015 00:46
-
-
Save mprymek/579d02f6c878cc37ef30 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Exlog do | |
defmacro __using__ _opts do | |
quote do | |
import Exlog | |
end | |
end | |
def new do | |
{:ok,e} = :erlog.new | |
e | |
end | |
# TODO: doesn't work... | |
#def new_ets do | |
# {:ok, e} = :erlog.load(:erlog_ets,Exlog.new) | |
# e | |
#end | |
# NOTE: We do not return context here! You can't use assert(...) etc. | |
defmacro provable?(e,ex_clause) do | |
clause = ex2erlog ex_clause | |
quote do | |
{_e,{result,_bind}} = Exlog.e_prove unquote(e), unquote(clause) | |
result | |
end | |
end | |
# @TODO: test clause is of form a <- b | |
defmacro assert!(e,ex_clause) do | |
meta_predicate :assert!, e, {:assert, ex2erlog(ex_clause)} | |
end | |
defmacro assertz!(e,ex_clause) do | |
meta_predicate :assertz!, e, {:assertz, ex2erlog(ex_clause)} | |
end | |
defp meta_predicate(pred_name,e,clause) do | |
quote do | |
case Exlog.e_prove unquote(e), unquote(clause) do | |
{e,{true,_}} -> e | |
{e,result} -> | |
raise "Exlog.#{unquote(pred_name)}(#{inspect unquote(clause)}) failed with #{inspect result}." | |
end | |
end | |
end | |
defmacro prove(e,ex_clause) do | |
clause = ex2erlog ex_clause | |
quote do | |
Exlog.e_prove unquote(e), unquote(clause) | |
end | |
end | |
defmacro prove_all(e,ex_clause) do | |
clause = ex2erlog ex_clause | |
quote do | |
Exlog.e_prove_all unquote(e), unquote(clause) | |
end | |
end | |
# clause | |
# format: f(a) <- [ g(a), h(b,c) ] LIST IS MANDATORY HERE! | |
def ex2erlog({:<-, meta, [head,body]}) when is_list(body) do | |
e_head = ex2erlog head | |
e_body = body |> Enum.map(&ex2erlog/1) | |
result = {:{}, meta, [:':-',e_head|e_body]} | |
#IO.puts "HEAD: #{inspect head}" | |
#IO.puts "E_HEAD: #{inspect Code.eval_quoted(e_head)}" | |
#IO.puts "BODY: #{inspect body}" | |
#IO.puts "E_BODY: #{inspect e_body}" | |
#IO.puts "RESULT: #{inspect result}" | |
result | |
end | |
# s.x | |
def ex2erlog(dot_expr={{:., _, [_, _]}, _, _}), do: dot_expr | |
# atom | |
def ex2erlog(atom) when is_atom(atom), do: atom | |
# number | |
def ex2erlog(num) when is_integer(num) or is_float(num), do: num | |
# Prolog variable | |
def ex2erlog({:__aliases__, meta, [atom]}) when is_atom(atom) do | |
{:{}, meta, [atom]} | |
end | |
def ex2erlog({:_, meta, mod}) when is_atom(mod) do | |
{:{}, meta, [:_]} | |
end | |
# functor | |
def ex2erlog({fun, meta, args}) when is_atom(fun) and is_list(args) and (not (fun in [:<-])) do | |
e_args = args |> Enum.map(&ex2erlog/1) | |
{:{}, meta, [fun|e_args]} | |
end | |
# Elixir variable | |
def ex2erlog({atom, meta, mod}) when is_atom(atom) and is_atom(mod) do | |
{atom, meta, mod} | |
end | |
# string | |
def ex2erlog(str) when is_binary(str), do: str | |
def ex2erlog(any) do | |
raise "Invalid clause: #{inspect any}" | |
end | |
def e_prove(e,clause) do | |
case :erlog.prove clause, e do | |
{{:succeed, bindings}, e} -> {e,{true,bindings}} | |
{:fail,e} -> {e,{false,[]}} | |
{{:error, err},e} -> raise "Exlog error: #{inspect err}" | |
end | |
end | |
def e_prove_all(e,clause) do | |
case :erlog.prove clause, e do | |
{{:succeed, bindings}, e} -> | |
next_solution e, [bindings] | |
{:fail,e} -> {e,[]} | |
{{:error, err},e} -> raise "Exlog error: #{inspect err}" | |
end | |
end | |
defp next_solution(e,bindings1) do | |
case :erlog.next_solution e do | |
{{:succeed, bindings}, e} -> | |
next_solution e, [bindings|bindings1] | |
{:fail,e} -> {e,Enum.reverse(bindings1)} | |
{{:error, err},e} -> raise "Exlog error: #{inspect err}" | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment