diff --git a/.gitignore b/.gitignore index 9989d01..7fb0396 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ _build/ comp_opts.mk erl_crash.dump +rebar.lock +src/erlog_scan.erl diff --git a/README.md b/README.md index 7c0dc56..66770bb 100644 --- a/README.md +++ b/README.md @@ -20,19 +20,19 @@ This is a low level interface, which is meant to built upon as much as used dire To create an Erlog instance in a closure use `erlog:new()` this will return `{ok, State}` Where state is the current state of the Erlog system. You should treat it as an opaque data structure. To prove a -clause or run Prolog code you can then run `erlog:prove(State, {...})` +clause or run Prolog code you can then run `erlog:prove({...}, State)` This will return a new closure and a return of type -`erlog_return()`. To consult a file you can run `erlog:consult(State, -FILE)` which will return a new closure and 'ok' or an error. +`erlog_return()`. To consult a file you can run `erlog:consult(FILE, State)` +which will return a new closure and 'ok' or an error. For example take this code: -We start by creating a new instance of the Erlog engine, then we +We start by creating a new instance of the Erlog engine, then we it starts with an append statement which ask it to append lists `A` and `B`. The return value is designated with a 1 tuple with an atom -value for the return variable, in this case `{'Z'}`. +value for the return variable, in this case `{'Z'}`. If the Prolog code works correctly it will return the tuple `{{succeed, -[{'Z', Value}]}, NewState}`. +[{'Z', Value}]}, NewState}`. @@ -46,6 +46,27 @@ If the Prolog code works correctly it will return the tuple `{{succeed, end ```` +### The simple Erlog shell. + +This is a simple shell similar to a "normal" Prolog shell. +An example, using a file from Erlog repository. + +````erlang + 1> erlog_shell:server(). + Erlog Shell V14.2.1 (abort with ^G) + | ?- consult("examples/family.pl"). + Yes + | ?- parent(pam, B). + B = bob + : + Yes + | ?- halt + . + ok + 2> +```` + + The dialyzer types of some of Erlog's functions are as such ````erlang @@ -66,15 +87,15 @@ If you have questions about Erlog post them tagged with Erlog on Stack Overflow If you want to pass data between Erlang and Prolog it is pretty easy to do so. Data types map pretty cleanly between the two languages due -to the fact that Erlang evolved from Prolog. +to the fact that Erlang evolved from Prolog. ### Atoms Atoms are the same in Erlang and Prolog, and can be passed back and forth without problem. -### Numeric Data +### Numeric Data Integer and floating point numbers similarly can be passed back and -forth. +forth. ### Opaque data @@ -87,17 +108,17 @@ comparisons on them. It is possible to send structured Erlang data to Prolog, and this is often very useful. Lists can be sent directly back and forth. Maps are not (Yet) supported, we will be looking into how to support them in -the future. +the future. Erlog understands Erlang tuples to be facts. So the Erlang tuple `{foo, 1, 2, 3}` would show up in Erlog as the fact `foo(1,2,3)`. The upshot of this is that all tuples that are passed to Erlog must have an atom as the first element and must have more than 1 element. The -tuple `{atom()}` will be understood to be a Prolog variable. +tuple `{atom()}` will be understood to be a Prolog variable. Records in Erlang are just tuples with an initial atom. So it is possible to pass records between Erlog and Erlang. The record -definition here and the Prolog fact are equivalent. +definition here and the Prolog fact are equivalent. ````erlang -record(person, {name, phone, address}). @@ -112,8 +133,8 @@ standard prolog arg/3 predicate. If you want to create functors that can access fields in an Erlang record by name, you can create functors for that Automaticly with the code in the file https://github.com/zkessin/erlog/blob/master/priv/records.pl. just -call `erlog:prove(State, {record, person, record_info(fields, -person)})`. Note that the record fields must be created in Erlang at +call `erlog:prove({record, person, record_info(fields, person)}, State)`. +Note that the record fields must be created in Erlang at compile time. ## Using ETS @@ -124,7 +145,7 @@ ETS table. It should also be possible to work with mnesia tables, but this has not yet been done. If you want to use Erlog with ETS you need to load the erlog_ets -module into Erlog. To do that you call `erlog:load(PID,erlog_ets)` or +module into Erlog. To do that you call `erlog:load(erlog_ets, PID)` or `E({load,erlog_ets})`. You can match on an ETS table with `ets_match(TableId, Value)`. @@ -151,8 +172,8 @@ If you want to run the tests you will need to install quickcheck mini to run the tests then run `rebar eunit` -## Licence +## Licence Erlog was created by Robert Virding and can be used under the -Apache 2.0 Licence. +Apache 2.0 Licence. diff --git a/src/erlog_shell.erl b/src/erlog_shell.erl index d0aed97..4a76a6d 100644 --- a/src/erlog_shell.erl +++ b/src/erlog_shell.erl @@ -41,6 +41,12 @@ server(M, A) -> server_loop(Erl0) -> case erlog_io:read('| ?- ') of {ok,halt} -> ok; + {ok,{consult, File}} -> + Erl1 = consult(erlog:consult(File,Erl0), Erl0), + server_loop(Erl1); + {ok,{reconsult, File}} -> + Erl1 = consult(erlog:reconsult(File,Erl0), Erl0), + server_loop(Erl1); {ok,Files} when is_list(Files) -> case reconsult_files(Files, Erl0) of {ok,Erl1} -> @@ -70,6 +76,13 @@ server_loop(Erl0) -> server_loop(Erl0) end. +consult({ok, State}, _) -> + io:fwrite("Yes\n"), + State; +consult({error, Error}, State) -> + io:fwrite("Error: ~s\n", [erlog_io:write1(Error)]), + State. + reconsult_files([F|Fs], Erl0) -> case erlog:reconsult(F, Erl0) of {ok,Erl1} -> reconsult_files(Fs, Erl1);