wip
This commit is contained in:
parent
91f0064a5b
commit
5135a55081
110
2
Normal file
110
2
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
% @doc a word is an ordset of ltrs
|
||||||
|
%
|
||||||
|
% This mathematically is a cluster of letters; so in "A + B + AB", this is one
|
||||||
|
% of the summands.
|
||||||
|
%
|
||||||
|
% multiplication is implied in a word
|
||||||
|
%
|
||||||
|
% empty word is 1
|
||||||
|
%
|
||||||
|
% anything times itself equals itself, so duplication is ignored
|
||||||
|
%
|
||||||
|
% multiplication = inclusive union
|
||||||
|
%
|
||||||
|
% operations assume all inputs are valid
|
||||||
|
-module(wfc_word).
|
||||||
|
|
||||||
|
-export_type([
|
||||||
|
word/0
|
||||||
|
]).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
%% constructors
|
||||||
|
one/0,
|
||||||
|
validate/1,
|
||||||
|
from_list/1, to_list/1,
|
||||||
|
%% ops
|
||||||
|
mul/2, mul/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
-opaque word() :: {w, ordsets:ordset(wfc_ltr:ltr())}.
|
||||||
|
|
||||||
|
%%----------------------------
|
||||||
|
%% constructor
|
||||||
|
%%----------------------------
|
||||||
|
|
||||||
|
-spec one() -> word().
|
||||||
|
|
||||||
|
one() ->
|
||||||
|
{w, []}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec validate(Word) -> Result
|
||||||
|
when Word :: word(),
|
||||||
|
Result :: ok
|
||||||
|
| {error, Reason :: string()}.
|
||||||
|
% @doc
|
||||||
|
% check each letter in the word for validity
|
||||||
|
%
|
||||||
|
% also check that word shape is valid
|
||||||
|
% @end
|
||||||
|
|
||||||
|
validate(W = {w, Letters}) ->
|
||||||
|
case from_list(Letters) of
|
||||||
|
{ok, Result} when Result =:= W ->
|
||||||
|
ok;
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
|
end;
|
||||||
|
validate(X) ->
|
||||||
|
{error, wfc_utils:str("wfc_word:validate: malformed word: ~tp", [X])}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec to_list(word()) -> Result
|
||||||
|
when Result :: {ok, [wfc_ltr:ltr()]}
|
||||||
|
| {error, string()}.
|
||||||
|
|
||||||
|
to_list({w, Ltrs}) -> {ok, Ltrs};
|
||||||
|
to_list(Bad) -> {error, wfc_utils:str("wfc_word:to_list: bad letter: ~tp", [Bad])}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec from_list(Ltrs) -> Result
|
||||||
|
when Ltrs :: list(wfc_ltr:ltr()),
|
||||||
|
Result :: {ok, word()}
|
||||||
|
| {error, Reason :: string()}.
|
||||||
|
|
||||||
|
from_list(Chars) ->
|
||||||
|
from_list(ordsets:from_list(Chars), []).
|
||||||
|
|
||||||
|
|
||||||
|
%% validate each letter
|
||||||
|
from_list([Ltr | Rest], Acc) ->
|
||||||
|
case wfc_ltr:validate(Ltr) of
|
||||||
|
ok -> from_list(Rest, [Ltr | Acc]);
|
||||||
|
Error -> Error
|
||||||
|
end;
|
||||||
|
% done, all good
|
||||||
|
from_list([], Acc) ->
|
||||||
|
{ok, {w, lists:reverse(Acc)}}.
|
||||||
|
|
||||||
|
|
||||||
|
%%----------------------------
|
||||||
|
%% ops
|
||||||
|
%%----------------------------
|
||||||
|
|
||||||
|
-spec mul(word(), word()) -> word().
|
||||||
|
% @doc product of two words
|
||||||
|
%
|
||||||
|
% assumes the words are valid
|
||||||
|
|
||||||
|
mul({w, X}, {w, Y}) ->
|
||||||
|
{w, ordsets:union(X, Y)}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec mul([word()]) -> word().
|
||||||
|
% @doc multiply a list of words together
|
||||||
|
|
||||||
|
mul([Word | Rest]) -> mul(Word, mul(Rest));
|
||||||
|
mul([]) -> one().
|
||||||
22
src/wfc.erl
Normal file
22
src/wfc.erl
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
% @doc
|
||||||
|
% porcelain wfc ops
|
||||||
|
-module(wfc).
|
||||||
|
|
||||||
|
-export_type([
|
||||||
|
sentence/0
|
||||||
|
]).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
|
||||||
|
zero/0, one/0,
|
||||||
|
add/1, add/2,
|
||||||
|
mul/1, mul/2
|
||||||
|
]).
|
||||||
|
|
||||||
|
|
||||||
|
-type sentence() :: wfc_sentence:sentence().
|
||||||
|
|
||||||
|
|
||||||
|
%% constructors
|
||||||
|
-spec
|
||||||
|
zero()
|
||||||
@ -1,4 +1,9 @@
|
|||||||
% @doc called ltr to disambiguate from
|
% @doc called ltr to disambiguate from "char"
|
||||||
|
%
|
||||||
|
% In "A + B + AB", this is one of the individual letters.
|
||||||
|
%
|
||||||
|
% a letter is a binary. atom is more natural representation but this is http,
|
||||||
|
% can't be spamming the atoms table.
|
||||||
%
|
%
|
||||||
% mathematically, this is a variable like "a", "b", "c", etc
|
% mathematically, this is a variable like "a", "b", "c", etc
|
||||||
-module(wfc_ltr).
|
-module(wfc_ltr).
|
||||||
@ -78,6 +83,9 @@ new2(Acc, Rest = <<BadChar:8, _/binary>>) ->
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
-spec to_binary(ltr()) -> binary().
|
-spec to_binary(ltr()) -> Result
|
||||||
|
when Result :: {ok, binary()}
|
||||||
|
| {error, string()}.
|
||||||
|
|
||||||
to_binary({c, X}) -> X.
|
to_binary({c, X}) -> {ok, X};
|
||||||
|
to_binary(Bad) -> {error, wfc_utils:str("wfc_ltr:to_binary: bad letter: ~tp", [Bad])}.
|
||||||
|
|||||||
75
src/wfc_sentence.erl
Normal file
75
src/wfc_sentence.erl
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
% @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).
|
||||||
|
|
||||||
|
-export_type([
|
||||||
|
sentence/0
|
||||||
|
]).
|
||||||
|
|
||||||
|
-export([
|
||||||
|
%% constructors
|
||||||
|
zero/0,
|
||||||
|
validate/1,
|
||||||
|
from_list/1, to_list/1,
|
||||||
|
%% ops
|
||||||
|
add/2, add/1
|
||||||
|
]).
|
||||||
|
|
||||||
|
-opaque sentence() :: {s, ordsets:ordset(wfc_word:word())}.
|
||||||
|
|
||||||
|
%%--------------------------
|
||||||
|
%% constructors
|
||||||
|
%%--------------------------
|
||||||
|
|
||||||
|
-spec zero() :: sentence().
|
||||||
|
|
||||||
|
zero() ->
|
||||||
|
{s, []}.
|
||||||
|
|
||||||
|
|
||||||
|
-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])}.
|
||||||
|
|
||||||
|
|
||||||
|
%%---------------------------
|
||||||
|
%% prim ops
|
||||||
|
%%---------------------------
|
||||||
|
|
||||||
|
add({s, X}, {s, Y}) -> {s, disjoint_union(X, Y)}.
|
||||||
|
|
||||||
|
disjoint_union(X, Y) ->
|
||||||
|
ordsets:subtract(ordsets:union(X, Y),
|
||||||
|
ordsets:intersection(X, Y)).
|
||||||
|
|
||||||
|
|
||||||
|
add([S | Rest]) -> add(S, add(Rest));
|
||||||
|
add([]) -> zero().
|
||||||
@ -1,10 +1,12 @@
|
|||||||
% @doc misc utility functions
|
% @doc misc utility functions
|
||||||
-module(wfc_utils).
|
-module(wfc_utils).
|
||||||
|
|
||||||
-export([err/2, emsg/2]).
|
-export([err/2, str/2, emsg/2]).
|
||||||
|
|
||||||
err(Fmt, Pat) ->
|
err(Fmt, Pat) ->
|
||||||
{error, emsg(Fmt, Pat)}.
|
{error, emsg(Fmt, Pat)}.
|
||||||
|
|
||||||
|
str(X, Y) -> emsg(X, Y).
|
||||||
|
|
||||||
emsg(Fmt, Pat) ->
|
emsg(Fmt, Pat) ->
|
||||||
unicode:characters_to_list(io_lib:format(Fmt, Pat)).
|
unicode:characters_to_list(io_lib:format(Fmt, Pat)).
|
||||||
|
|||||||
@ -1,10 +1,17 @@
|
|||||||
% @doc a word is an ordset of ltrs
|
% @doc a word is an ordset of ltrs
|
||||||
%
|
%
|
||||||
|
% This mathematically is a cluster of letters; so in "A + B + AB", this is one
|
||||||
|
% of the summands.
|
||||||
|
%
|
||||||
% multiplication is implied in a word
|
% multiplication is implied in a word
|
||||||
%
|
%
|
||||||
% empty word is 1
|
% empty word is 1
|
||||||
%
|
%
|
||||||
% anything times itself equals itself, so duplication is ignored
|
% anything times itself equals itself, so duplication is ignored
|
||||||
|
%
|
||||||
|
% multiplication = inclusive union
|
||||||
|
%
|
||||||
|
% operations assume all inputs are valid
|
||||||
-module(wfc_word).
|
-module(wfc_word).
|
||||||
|
|
||||||
-export_type([
|
-export_type([
|
||||||
@ -15,7 +22,7 @@
|
|||||||
%% constructors
|
%% constructors
|
||||||
one/0,
|
one/0,
|
||||||
validate/1,
|
validate/1,
|
||||||
from_ltrs/1, to_ltrs/1,
|
from_list/1, to_list/1,
|
||||||
%% ops
|
%% ops
|
||||||
mul/2, mul/1
|
mul/2, mul/1
|
||||||
]).
|
]).
|
||||||
@ -32,26 +39,54 @@ one() ->
|
|||||||
{w, []}.
|
{w, []}.
|
||||||
|
|
||||||
|
|
||||||
validate(_) -> error(nyi).
|
-spec validate(Word) -> Result
|
||||||
to_ltrs(_) -> error(nyi).
|
when Word :: word(),
|
||||||
|
Result :: ok
|
||||||
|
| {error, Reason :: string()}.
|
||||||
|
% @doc
|
||||||
|
% check each letter in the word for validity
|
||||||
|
%
|
||||||
|
% also check that word shape is valid
|
||||||
|
% @end
|
||||||
|
|
||||||
-spec from_ltrs(Ltrs) -> Result
|
validate(W = {w, Letters}) ->
|
||||||
|
case from_list(Letters) of
|
||||||
|
{ok, Result} when Result =:= W ->
|
||||||
|
ok;
|
||||||
|
Error ->
|
||||||
|
Error
|
||||||
|
end;
|
||||||
|
validate(X) ->
|
||||||
|
{error, wfc_utils:str("wfc_word:validate: malformed word: ~tp", [X])}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec to_list(word()) -> Result
|
||||||
|
when Result :: {ok, [wfc_ltr:ltr()]}
|
||||||
|
| {error, string()}.
|
||||||
|
|
||||||
|
to_list({w, Ltrs}) -> {ok, Ltrs};
|
||||||
|
to_list(Bad) -> {error, wfc_utils:str("wfc_word:to_list: bad letter: ~tp", [Bad])}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-spec from_list(Ltrs) -> Result
|
||||||
when Ltrs :: list(wfc_ltr:ltr()),
|
when Ltrs :: list(wfc_ltr:ltr()),
|
||||||
Result :: {ok, word()}
|
Result :: {ok, word()}
|
||||||
| {error, Reason :: string()}.
|
| {error, Reason :: string()}.
|
||||||
|
|
||||||
from_ltrs(Chars) ->
|
from_list(Chars) ->
|
||||||
from_ltrs(ordsets:from_list(Chars), []).
|
from_list(ordsets:from_list(Chars), []).
|
||||||
|
|
||||||
|
|
||||||
%% validate each letter
|
%% validate each letter
|
||||||
from_ltrs([Ltr | Rest], Acc) ->
|
from_list([Ltr | Rest], Acc) ->
|
||||||
case wfc_ltr:validate(Ltr) of
|
case wfc_ltr:validate(Ltr) of
|
||||||
ok -> from_ltrs(Rest, [Ltr | Acc]);
|
ok -> from_list(Rest, [Ltr | Acc]);
|
||||||
Error -> Error
|
Error -> Error
|
||||||
end;
|
end;
|
||||||
% done, all good
|
% done, all good
|
||||||
from_ltrs([], Acc) ->
|
from_list([], Acc) ->
|
||||||
{ok, {w, lists:reverse(Acc)}}.
|
{ok, {w, lists:reverse(Acc)}}.
|
||||||
|
|
||||||
|
|
||||||
@ -73,3 +108,6 @@ mul({w, X}, {w, Y}) ->
|
|||||||
|
|
||||||
mul([Word | Rest]) -> mul(Word, mul(Rest));
|
mul([Word | Rest]) -> mul(Word, mul(Rest));
|
||||||
mul([]) -> one().
|
mul([]) -> one().
|
||||||
|
|
||||||
|
|
||||||
|
add(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user