% @doc a sentence is an ordset of words % % in "A + B + AB", this is the full expression % % summation is implied in a sentence % % empty sentence is 0 -module(wfc_sentence). -vsn("0.2.0"). -export_type([ sentence/0 ]). -export([ %% constructors zero/0, one/0, validate/1, from_list/1, to_list/1, %% ops add/2, add/1, mul/2, mul_wxs/2, mul/1, %%% from_ from_ltr/1, from_word/1 ]). -opaque sentence() :: {s, ordsets:ordset(wfc_word:word())}. %%-------------------------- %% constructors %%-------------------------- -spec zero() -> sentence(). % @doc the 0-sentence is the empty sentence zero() -> {s, []}. -spec one() -> sentence(). % @doc the 1-sentence is the sentence that contains only the 1-word one() -> {s, [wfc_word:one()]}. -spec from_list(Words) -> Result when Words :: [wfc_word:word()], Result :: {ok, sentence()} | {error, string()}. from_list(Words) -> from_list(ordsets:from_list(Words), []). %% validate each word from_list([W | Rest], Acc) -> case wfc_word:validate(W) of ok -> from_list(Rest, [W | Acc]); Error -> Error end; % done, all good from_list([], Acc) -> {ok, {s, lists:reverse(Acc)}}. -spec to_list(sentence()) -> Result when Result :: {ok, [wfc_word:word()]} | {error, string()}. to_list({s, Words}) -> {ok, Words}; to_list(Bad) -> {error, wfc_utils:str("wfc_sentence:to_list: bad sentence: ~tp", [Bad])}. -spec validate(sentence()) -> ok | {error, string()}. validate({s, [W | Rest]}) -> case wfc_word:validate(W) of ok -> validate({s, Rest}); Error -> Error end; validate({s, []}) -> ok; validate(Bad) -> {error, wfc_utils:str("wfc_sentence:validate: bad sentence: ~tp", [Bad])}. %%--------------------------- %% prim ops %%--------------------------- -spec add(sentence(), sentence()) -> sentence(). add({s, X}, {s, Y}) -> {s, symdiff(X, Y)}. symdiff(X, Y) -> ordsets:subtract(ordsets:union(X, Y), ordsets:intersection(X, Y)). -spec add([sentence()]) -> sentence(). add([S | Rest]) -> add(S, add(Rest)); add([]) -> zero(). %%--------------------------- %% spec ops %%--------------------------- -spec mul(sentence(), sentence()) -> sentence(). mul({s, [W | Rest]}, S) -> %% (W + Rest) * S = W*S + Rest*S add(mul_wxs(W, S), mul({s, Rest}, S)); mul({s, []}, _) -> %% first arg 0 = result 0 zero(). -spec mul([sentence()]) -> sentence(). % @doc % multiply a list of sentences together; mul([]) = {s, {w, []}} mul([S | Rest]) -> mul(S, mul(Rest)); mul([]) -> one(). -spec mul_wxs(wfc_word:word(), sentence()) -> sentence(). mul_wxs(W, {s, [X | Rest]}) -> % W * (X + Rest) = W*X + W*Rest add({s, [wfc_word:mul(W, X)]}, mul_wxs(W, {s, Rest})); mul_wxs(_, {s, []}) -> zero(). %%--------------------------- %% from_ %%--------------------------- -spec from_ltr(term()) -> {ok, sentence()} | {error, string()}. from_ltr(Ltr) -> case wfc_word:from_ltr(Ltr) of {ok, Word} -> from_word(Word); Error -> Error end. -spec from_word(term()) -> {ok, sentence()} | {error, string()}. from_word(Word) -> from_list([Word]).