

Function("Substitute",{body,predicate,change})
[
  Substitute(body);
];
HoldArg("Substitute",predicate);
HoldArg("Substitute",change);
UnFence("Substitute",3);
RuleBase("Substitute",{body});
UnFence("Substitute",1);

Rule("Substitute",1,1,Apply(predicate,{body}) = True)
[
  Apply(change,{body});
];
Rule("Substitute",1,2,IsFunction(body))
[
  Apply("MapArgs",{body,"Substitute"});
];
Rule("Substitute",1,3,True) body;

/*Extremely hacky workaround, MacroSubstitute is actually the same as Substitute,
  but without re-evaluating its arguments. I could not just change Substitute, as
  it changed behaviour such that tests started to break.
 */
Function("MacroSubstitute",{body,predicate,change})
[
  `MacroSubstitute((Hold(@body)));
];
HoldArg("MacroSubstitute",predicate);
HoldArg("MacroSubstitute",change);
UnFence("MacroSubstitute",3);
RuleBase("MacroSubstitute",{body});
UnFence("MacroSubstitute",1);

Rule("MacroSubstitute",1,1,`ApplyPure(predicate,{Hold(Hold(@body))}) = True)
[
  `ApplyPure(change,{Hold(Hold(@body))});
];
Rule("MacroSubstitute",1,2,`IsFunction(Hold(@body)))
[
  `ApplyPure("MacroMapArgs",{Hold(Hold(@body)),"MacroSubstitute"});
];
Rule("MacroSubstitute",1,3,True)
[
 `Hold(@body);
];



LocalSymbols(predicate,list,result,item)
[
  Function("Select",{predicate,list})
  [
    Local(result);
    result:={};
    ForEach(item,list)
    [
      If(Apply(predicate,{item}),DestructiveAppend(result,item));
    ];
    result;
  ];
  HoldArg("Select",predicate);
  UnFence("Select",2);
];
