anchor.diff:  flatten(Q) ->
       [Q].
   
  +partition(Qs) ->
  +    {Pos,Neg} = lists:partition(fun (Q) -> is_record(Q, term_q) end, Qs),
  +    {terms(Pos),terms(Neg)}.
  +
  +terms(Qs) ->
  +    lists:usort([term(Q) || Q <- Qs]).
  +
  +term({not_q,{term_q,T}}) ->
  +    T;
  +term({term_q,T}) ->
  +    T.
  +
  +fetch(K) ->
  +    {K, case dk_pp:terms(K, "en") of                % FIXME: hardcoded lang
  +            [] ->
  +                gb_sets:new();
  +            [T|[]] ->
  +                dk_idx:doc_ids(T);
  +            Ts ->
  +                gb_sets:intersection(plists:map(fun dk_idx:doc_ids/1, Ts))
  +        end}.
  +
   %%----------------------------------------------------------------------------
   %% PropErties
   %%----------------------------------------------------------------------------
  
positive.code: %% API
  %%----------------------------------------------------------------------------
  
  clauses(Str) ->
      [flatten(X) || X <- and_subs(dnf(from_str(Str)))].
  
  %%----------------------------------------------------------------------------
  %% Internal functions
  
negative.code: -include_lib("proper/include/proper.hrl").
  
  %% API
  -export([execute/1]).
  -export([prepare/1]).
  
  %% Record declarations
  -record(and_q,  {l_sub :: q(), r_sub :: q()}).
  