fewd/src/wfc_eval_context.erl

114 lines
3.0 KiB
Erlang

-module(wfc_eval_context).
-vsn("0.2.0").
-export_type([
context/0
]).
-export([
new/0,
default/0,
default_snowflakes/0,
define/3,
undefine/2,
resolve_pattern/2,
resolve_snowflake/2
]).
-type sentence() :: wfc_sentence:sentence().
-record(ctx,
{snowflakes = #{} :: #{binary() := fun(([sentence()]) -> {ok, sentence()} | {error, string()})},
patterns = #{} :: #{binary() := sentence()}}).
-opaque context() :: #ctx{}.
new() ->
#ctx{snowflakes = #{},
patterns = #{}}.
default() ->
#ctx{snowflakes = default_snowflakes()}.
default_snowflakes() ->
#{<<"and">> => fun wfc:mul/1,
<<"xor">> => fun wfc:add/1,
<<"implies">> => fun snf_implies/1,
<<"ior">> =>
fun IOR([S1 | Rest]) ->
case IOR(Rest) of
{ok, S2} -> {ok, sf_ior(S1, S2)};
Error -> Error
end;
IOR([]) ->
{ok, wfc:one()}
end,
<<"not">> =>
fun ([S]) -> {ok, sf_not(S)};
(Bad) -> {error, wfc_utils:str("not/1: wrong number of arguments: ~p", [Bad])}
end,
<<"impliedby">> =>
fun ([A, B]) -> {ok, sf_impliedby(A, B)};
(Bad) -> {error, wfc_utils:str("impliedby/2: wrong number of arguments: ~p", [Bad])}
end,
<<"iff">> =>
fun ([A, B]) -> {ok, sf_iff(A, B)};
(Bad) -> {error, wfc_utils:str("iff/2: wrong number of arguments: ~p", [Bad])}
end
}.
snf_implies([A, B]) -> {ok, sf_implies(A, B)};
snf_implies(Bad) -> {error, wfc_utils:str("implies/2: wrong number of arguments: ~p", [Bad])}.
sf_ior(A, B) ->
wfc_sftt:appl_ttf(fun ttf_ior/2, [A, B]).
sf_not(A) ->
{ok, Result} = wfc:add([wfc_sentence:one(), A]),
Result.
sf_implies(A, B) ->
wfc_sftt:appl_ttf(fun ttf_implies/2, [A, B]).
sf_impliedby(A, B) ->
sf_implies(B, A).
sf_iff(A, B) ->
{ok, Result} = wfc:mul([sf_implies(A, B), sf_impliedby(A, B)]),
Result.
ttf_ior(0, 0) -> 0;
ttf_ior(1, 0) -> 1;
ttf_ior(0, 1) -> 1;
ttf_ior(1, 1) -> 1.
ttf_implies(0, 0) -> 1;
ttf_implies(1, 0) -> 0;
ttf_implies(0, 1) -> 1;
ttf_implies(1, 1) -> 1.
define(Pat, Sentence, Ctx = #ctx{patterns = OldPatterns}) ->
NewPatterns = maps:put(Pat, Sentence, OldPatterns),
{ok, Ctx#ctx{patterns = NewPatterns}}.
undefine(Pat, Ctx = #ctx{patterns = OldPatterns}) ->
NewPatterns = maps:remove(Pat, OldPatterns),
{ok, Ctx#ctx{patterns = NewPatterns}}.
resolve_pattern(Pat, Ctx = #ctx{patterns = Patterns}) ->
case maps:find(Pat, Patterns) of
error -> {error, wfc_utils:str("wfc_eval_context:resolve_pattern: not found: ~s; context: ~w", [Pat, Ctx])};
Result -> Result
end.
resolve_snowflake(SF, Ctx = #ctx{snowflakes = Snowflakes}) ->
case maps:find(SF, Snowflakes) of
error -> {error, wfc_utils:str("wfc_eval_context:resolve_snowflake: not found: ~s; context: ~w", [SF, Ctx])};
Result -> Result
end.