
Function("Flatten",{body,oper})
[
  DoFlatten(body);
];

RuleBase("DoFlatten",{doflattenx});
UnFence("DoFlatten",1);

Rule("DoFlatten",1,1,Type(doflattenx)=oper)
    Apply("Concat",MapSingle("DoFlatten",Tail(Listify(doflattenx))));
Rule("DoFlatten",1,2,True) {doflattenx};





Function("GroupIndex",{list,element})
[
  Local(result,count);
  result:= -1;
  count:=1;
  While(result<0 And list != {})
  [
    If((list[[1]][[1]]) = element,
      result := count
      );
    list:=Tail(list);
    count++;
  ];
  result;
];


Function("ExplodeTerm",{list})
[
  Local(compact,exponents,const,combined,index);
  consts:={};
  compact:={};

  ForEach(item,list)
  [
    If (IsRationalOrNumber(item),
       DestructiveAppend(consts,item),
       [
         index:=GroupIndex(compact,item);
         If (index>0,
            compact[[index]][[2]]:=(compact[[index]][[2]])+1,
            DestructiveInsert(compact,1,{item,1})
            );
       ]);     
  ];

  {consts,compact};
];

Function("ImplodeTerm",{list,oper,multi,unity})
[
  Local(cnst,term,fact);
  cnst:=unity;
  term:=unity;
  ForEach(item,list[[1]])
  [
    cnst:=Apply("Apply",{oper,{cnst,item}});
  ];
  ForEach(item,list[[2]])
  [
    fact:=Apply("Apply",{multi,{Simplify(item[[1]]),item[[2]]}});
    term:=Apply("Apply",{oper,{fact,term}});
  ];
  Apply("Apply",{oper,{cnst,term}});
];

RuleBase("Simplify",{expr});

Rule("Simplify",1,1,Type(expr)="*") ImplodeTerm(ExplodeTerm(Flatten(expr,"*")),"*","^",1);
Rule("Simplify",1,1,Type(expr)="+") ImplodeTerm(ExplodeTerm(Flatten(expr,"+")),"+",{{x,y},y*x},0);
Rule("Simplify",1,10,IsFunction(expr)) MapArgs(expr,"Simplify");
Rule("Simplify",1,10,True) expr;


