stopping point
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
-module(gsc_ntree).
|
||||
|
||||
-export_type([
|
||||
ntree/2,
|
||||
ntree/0
|
||||
]).
|
||||
|
||||
-export([
|
||||
nstem/2,
|
||||
flatten/1,
|
||||
deleaf0/1,
|
||||
releaf0/2
|
||||
]).
|
||||
|
||||
|
||||
-include("$gsc_include/gsc.hrl").
|
||||
|
||||
%%=====================================================
|
||||
%% API: types
|
||||
%%=====================================================
|
||||
|
||||
-record(ns, {val :: any(), kids :: list(any())}).
|
||||
-record(nl, {val :: any()}).
|
||||
|
||||
%% @doc ntree(S, L) is a "node tree" (meaning stems
|
||||
%% have values and children)
|
||||
-type ntree(S, L)
|
||||
:: #ns{val :: S, kids :: [ntree(S, L)]}
|
||||
| #nl{val :: L}.
|
||||
|
||||
-type ntree() :: ntree(any(), any()).
|
||||
|
||||
|
||||
%%=====================================================
|
||||
%% API: functions
|
||||
%%=====================================================
|
||||
|
||||
|
||||
-spec nstem(Root, List) -> Tree when
|
||||
Root :: X,
|
||||
List :: list(Y),
|
||||
Tree :: ntree(X, Y),
|
||||
X :: any(),
|
||||
Y :: any().
|
||||
% @doc
|
||||
% You *probably* want `releaf0/2' instead.
|
||||
%
|
||||
% This function naively wraps each element in the list
|
||||
% in a leaf type, even if it's already wrapped.
|
||||
%
|
||||
% nstem(root, [Foo, Bar, Baz]) ~>
|
||||
% *s root
|
||||
% |
|
||||
% +--- .l Foo
|
||||
% |
|
||||
% +--- .l Bar
|
||||
% |
|
||||
% +--- .l Baz
|
||||
%
|
||||
% Much more common use case is to releaf only the input
|
||||
% nodes which are not already wrapped, which is what
|
||||
% `releaf0/2' does.
|
||||
% @end
|
||||
nstem(Root, List) ->
|
||||
{ns, Root, [{nl, Y} || Y <- List]}.
|
||||
|
||||
|
||||
|
||||
-spec flatten(Tree) -> LeafVals when
|
||||
Tree :: ntree(any(), LeafType),
|
||||
LeafVals :: [LeafType],
|
||||
LeafType :: any().
|
||||
|
||||
flatten({nl, X}) ->
|
||||
[X];
|
||||
flatten({ns, _, Keeids}) ->
|
||||
lists:flatten([flatten(Keeid) || Keeid <- Keeids]).
|
||||
|
||||
|
||||
|
||||
-spec deleaf0(Tree) -> Result when
|
||||
Tree :: ntree(S, L),
|
||||
Result :: [L | Tree],
|
||||
S :: any(),
|
||||
L :: any().
|
||||
|
||||
% @doc unwrap the leaf children, and leave the stem
|
||||
% children intact
|
||||
%
|
||||
% ex. 1:
|
||||
% (+ 1 2 (* 3 4) 5)
|
||||
% ~> '(1 2 (* 3 4) 5)
|
||||
%
|
||||
% ex. 2:
|
||||
% {ns, '+', [{nl, 1},
|
||||
% {nl, 2},
|
||||
% {ns, '*', [{nl, 3}, {nl, 4}]},
|
||||
% {nl, 5}]}
|
||||
% ~> [1, 2, {ns, '*', [{nl, 3}, {nl, 4}]}, 5]
|
||||
% @end
|
||||
deleaf0({nl, L}) -> [L];
|
||||
deleaf0({ns, _, Ls}) -> dl0([], Ls).
|
||||
|
||||
dl0(Stk, []) -> lists:reverse(Stk);
|
||||
dl0(Stk, [{nl, X} | Rest]) -> dl0([X | Stk], Rest);
|
||||
dl0(Stk, [X | Rest]) -> dl0([X | Stk], Rest).
|
||||
|
||||
|
||||
|
||||
-spec releaf0(Root, Keeids) -> Rooted when
|
||||
Root :: S,
|
||||
Keeids :: [L | ntree(S, L)],
|
||||
Rooted :: ntree(S, L),
|
||||
S :: any(),
|
||||
L :: any().
|
||||
|
||||
% @doc notional inverse of `deleaf0/1'
|
||||
%
|
||||
% Note that this does **NOT** double-wrap leafs in the
|
||||
% input
|
||||
releaf0(Root, Ks) ->
|
||||
#ns{val = Root,
|
||||
kids = lists:map(fun rl0/1, Ks)}.
|
||||
|
||||
rl0(X = #ns{}) -> X;
|
||||
rl0(X = #nl{}) -> X;
|
||||
rl0(X) -> {nl, X}.
|
||||
Reference in New Issue
Block a user