-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.