is_descendant(A, B) ->
lists:all(fun ({Actor, Event}) ->
Event =< proplists:get_value(Actor, B, -1)
end, A).
compare(A, B) ->
A_in_B = is_descendant(A, B),
B_in_A = is_descendant(B, A),
{A_in_B,
B_in_A,
A_in_B and B_in_A,
not (A_in_B or B_in_A}}.
The function `is_descendant` is nearly a translation of your APL code. I'm not convinced that we need APL on the Beam, for the quality of this VM certainly isn't in its array processing capabality... but I was expecting the argument "such an array-oriented language would motivate improvements in this direction", which is definitively true!APL-enthousiasts often forget that APL forces you to use its builtin operators, while modern languages provide means to implement them (and aren't restricted to arrays). lists:all isn't a builtin in Erlang, but does it really matters that you can write it as `^/` in APL?
Note for functional programmers: `^` is the boolean AND operator, `/` is `fold`, and somehow there's an APL builtin hack so that `fold` knows that 1 (true) is the monoid identity of `AND`... but really `^/` is a compact notation for `fold (&&) True`
For completness:
all(_, []) -> true.
all(Pred, [X | Xs]) -> Pred(X) andalso all(Pred, Xs).
get_value(_, [], Default) -> Default;
get_value(K, [{K, V} | _], _) -> V;
get_value(K, [_ | Rest], Default) -> get_value(K, Rest, Default).