159 lines
3.2 KiB
Erlang
159 lines
3.2 KiB
Erlang
% @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]).
|