3 %%% Erlang implementation of a `same-fringe' solver.
5 -module('erlang-fringe').
6 -export([main/0, tree_fringe/1]).
8 %%%--------------------------------------------------------------------------
9 %%% Iteration protocol.
11 %% An iterator is a process I which responds to the message {next, P} by
12 %% sending to process P either {item, I, X} or {done, I}. (The iterator's
13 %% process id helps us work out which iterator we're getting a reply from.)
16 %% Called from an iterator: yield the term X.
18 {next, P} -> P ! {item, self(), X}
22 %% Fetch the next item from the iterator I, as a tuple {item, X}, or the
23 %% symbol `done' if there's nothing left..
26 {item, I, X} -> {item, X};
31 %% Create and return an iterator process given a function F in module M,
32 %% passing it the argument list A.
36 {next, P} -> P ! {done, self()}
41 %% Apply F to each item returned from the iterator I. Return the atom
51 iterators_equal(I, J) ->
52 %% Answer whether the iterators I and J return the same elements, as
53 %% decided by pattern-matching.
58 {{item, Z}, {item, Z}} -> iterators_equal(I, J);
62 %%%--------------------------------------------------------------------------
65 %% A tree is either the atom `nil' or a tuple {LEFT, DATUM, RIGHT} of the
66 %% LEFT and RIGHT subtrees and the DATUM, which may be any term.
68 %% Iteration is easy. We just use a separate process.
69 tree_fringe({L, D, R}) ->
76 %% Parse a tree from a textual description. The syntax is simple:
78 %% tree ::= empty | `(' tree char tree `)'
80 %% where the ambiguity is resolved by declaring that a `(' is a tree if we're
82 do_parse_tree([$( | S]) ->
83 case do_parse_tree(S) of
85 case do_parse_tree(SS) of
86 {R, [$) | SSS]} -> {{L, D, R}, SSS};
87 _ -> throw({simple_error, "missing )"})
90 throw({simple_error, "no data"})
96 case do_parse_tree(S) of
98 _ -> throw({simple_error, "trailing junk"})
101 %%%--------------------------------------------------------------------------
106 case init:get_plain_arguments() of
109 I = iterator('erlang-fringe', tree_fringe, [T]),
110 map_iterator(I, fun(X) -> io:put_chars([X]) end),
113 I = iterator('erlang-fringe', tree_fringe, [parse_tree(S)]),
114 J = iterator('erlang-fringe', tree_fringe, [parse_tree(SS)]),
115 case iterators_equal(I, J) of
116 true -> io:format("match~n");
117 _ -> io:format("no match~n")
120 throw({simple_error, "bad args"})
124 io:format(standard_error, "erlang-fringe: ~s~n", [M]),
129 %%%----- That's all, folks --------------------------------------------------