Code covered by the BSD License  

Highlights from
func2func.m v1.0 (Jul 2009)

func2func.m v1.0 (Jul 2009)

by

 

Updates anonymous function workspace. Workaround of STR2FUNC(FUNC2STR(f)) problem.

func2func(F,varargin)
function F = func2func(F,varargin)
%FUNC2FUNC   Updates anonymous function workspace.
%
%   SYNTAX:
%           F = func2func(F);
%           F = func2func(F,'base');
%           F = func2func(F,...,'VarName',VarValue);
%           F = func2func(F,...,VarStruct);
%
%   INPUT:
%     F       - Function handle or name or anonymous definition, as a
%               single input or in a cell or structure array.
%     'base'  - Updates function workspace with variables from 'base'
%               workspace. Use 'caller' to use the workspace from within
%               the function that calls this one. See EVALIN for details.
%               DEFAULT: 'caller' (Not used by default if 'VN',VV is used)
%     'VN',VV - Pair inputs specifying the variable name to be updated with
%               its corresponding value. Or it may be a variable structure,
%               with variable names as fields: VarStruct.VN = VV.
%               DEFAULT: (not used by default)
%
%   OUTPUT:
%     F - Updated function handle.
%
%   DESCRIPTION:
%     Anonymous functions is a great tool created since MATLAB v7. As you
%     know, you can create an anonymous function with/without arguments
%     but also with variables on your current workspace. For example,
%      >> A = 10;
%      >> F = @(x) A*x;
%    gives
%      >> F(5)
%      ans = 
%           50 
%    But, if you change the A value, it is not updated in the function
%    definition.
%      >> A = 20;
%      >> F(5)
%      ans = 
%           50
%    So, A is still 10 in F workspace. This is sometimes undesirable, and
%    one should update once again F to get the new A.
%      >> F = @(x) A*x;
%      >> F(5)
%      ans = 
%           100
%    But i) what happens if I only have the function handle? That is, I
%    cannot updated like in the last step. One can think in use the
%    FUNC2STR and STR2FUNC utilities as in:
%      >> G = str2func(func2str(F));
%    but, besides it returns a warning, the workspace of F is not
%    transfered to G. So, one is forced to use the EVAL way:
%      >> A = 30;
%      >> F = eval(func2str(F));
%      >> F(5)
%      ans = 
%           150
%    and the problem is solved. But, an error occurs if F is not an
%    anonymous function. This programs solves this problems and offers new
%    options like updating only specific variables, or using variables from
%    an specific workspace ('caller' o 'base'), F may be a cell of function
%    handles, or an structure, or a function name string or anonymous
%    definition.
%
%    Besides, you can even define variables existing only on the function
%    workspace like in:
%      >> clear A
%      >> F = func2func(@(x)A*x,'A',40);
%      >> F(5)
%        ans = 
%             200
%    Enjoy it!
%
%   NOTE:
%     * Optional inputs use its DEFAULT value when not given or [].
%     * When given specific variables definition (either by pair inputs or
%       an structure) the workspace is not used by default. To force the
%       use of any of 'base' or 'caller' workspace give it in the second
%       input.
%     * When any variable in the anonymous function remains undefined, a
%       warning is returned. To eliminate this warning use
%         >> warning('off','CVARGAS:func2func:undefinedVariableOrFunction')
%       before the use of this function.
%
%   EXAMPLE:
%     A = 5;
%     F = @(x)A*x;
%     F(1) % RESULT: 5
%     A = 8;
%     F(1) % RESULT: 5
%     F = func2func(F);
%     F(1) % RESULT: 8, with updated A value.
%    
%   SEE ALSO:
%     FUNCTION_HANDLE, FUNCTIONS, FUNC2STR and STR2FUNC.
%     
%
%
%   ---
%   MFILE:   func2func.m
%   VERSION: 1.0 (Jul 29, 2009) (<a href="matlab:web('http://www.mathworks.com/matlabcentral/fileexchange/authors/11258')">download</a>) 
%   MATLAB:  7.7.0.471 (R2008b)
%   AUTHOR:  Carlos Adrian Vargas Aguilera (MEXICO)
%   CONTACT: nubeobscura@hotmail.com

%   REVISIONS:
%   1.0      Released. (Jul 29, 2009)

%   DISCLAIMER:
%   func2func.m is provided "as is" without warranty of any kind, under the
%   revised BSD license.

%   Copyright (c) 2009 Carlos Adrian Vargas Aguilera


% INPUTS CHECK-IN
% -------------------------------------------------------------------------

% Default.
ws      = 'caller'; % Default workspace. One of 'caller' or 'base'.
forceWs = false;    % Forces to use the WS when variable name/value given.

% Checks number of inputs and outputs.
if     nargin<1
 error('CVARGAS:func2func:notEnoughInputs',...
  'At least 1 input is required.')
elseif nargout>1
 error('CVARGAS:func2func:tooManyOutputs',...
  'At most 1 output is allowed.')
end

% Checks F input and forces it to be a cell array.
if isempty(F), return, end
[F,type,fieldNames] = checkF(F);

% Parse varargin.
[ws,forceWs,uWs] = parseVarargin(ws,forceWs,varargin{:});
clear varargin


% -------------------------------------------------------------------------
% MAIN
% -------------------------------------------------------------------------

% Gets number of functions.
N = numel(F);

% Main loop.
for n = 1:N
 
 % Gets function properties.
 fWs = functions(F{n});

 % Checks if anonymous. If not, there is nothing to update.
 if ~strcmp(fWs.type,'anonymous'), continue, end

 % Gets function defnition (string).
 if length(fWs.workspace)==1
  fDef = fWs.function;
 else
  fDef = func2str(fWs.workspace{2}.F);
 end
 
 % Gets function workspace.
 fWs = fWs.workspace{1};

 % Gets function workspace variable names.
 var  = fieldnames(fWs);
 Nvar = length(var);
 
 % Looks for hidden variables.
 if strcmp(fDef(2),'(')
  ind = regexp(fDef,'[)]','once');
  inp = symvar(fDef(1:ind));
  war = symvar(fDef(ind+1:end)); war = {war{:}};
  war(cellfun(@(x)any(strcmp(x,inp)),war)) = [];
  war(cellfun(@(x)any(strcmp(x,var)),war)) = [];
  var = {var{:},war{:}};
 else
  war = {};
 end

 % If no variables, there is nothing to update.
 if isempty(var), continue, end
 
 % a) Evaluates function F variables on THIS function workspace.
 for k = 1:Nvar
  eval([var{k} ' = fWs.(var{k});'])
 end

 % b) Evaluates workspace WS variables on THIS function workspace.
 if forceWs
  for k = 1:length(var)
   try
    eval([var{k} ' = evalin(ws,var{k});'])
   catch
    % continue
   end
  end
 end

 % c) Evaluates user specified variables on THIS function workspace.
 uar = fieldnames(uWs);
 for k = 1:numel(uar)
  eval([uar{k} ' = uWs.(uar{k});'])
 end

 % finally, updates function.
 F{n} = eval(fDef);
 
 % Checks if all variables were updated.
 if ~isempty(war)
  war(cellfun(@(x)exist(x,'var')==1,war)) = [];
  if ~isempty(war)
   Nw = length(war);
   if Nw==1, temp = []; else temp = Nw-1; end
   list           = war; 
   list(2,1:Nw-2) = {''', '''};
   list(2,temp)   = {''' and '''};
   list(2,Nw)     = {'''.'};
   list           = {'''' list{:}};
   list           = [list{:}];
   warning('CVARGAS:func2func:undefinedVariableOrFunction',...
    ['The following variable(s) or function(s) on "' fDef ...
     '" remained undefined: ' list])
  end
 end
 
 % Deletes generated workspace.
 clear(var{:},uar{:})
 
end


% OUTPUTS CHECK-OUT
% -------------------------------------------------------------------------

switch type
 case 'function_handle' 
  F = F{1};
 case 'cell'
  %continue'
 case 'structure'
  F = cell2struct(F,fieldNames,1);
end


% =========================================================================
% SUBFUNCTIONS
% -------------------------------------------------------------------------

function [F,type,fieldNames] = checkF(F)
% Checks F input and forces it to be a cell array.
fieldNames = [];
if isa(F,'function_handle')
 type = 'function_handle';
 F = {F};
elseif iscell(F)
 type = 'cell';
 % Check functions.
 ind = ~cellfun(@(x)isa(x,'function_handle'),F);
 if any(ind)
  if ~all(cellfun(@ischar,F(ind)))
   error('CVARGAS:func2func:invalidCellFunctionChar',...
    ['Elements of cell function must be either function handles, name ' ...
    'or anonymous definition string.'])
  end
  F(ind) = cellfun(@str2func2,F(ind),'UniformOutput',false);
 end
elseif isstruct(F)
 type       = 'structure';
 fieldNames = fieldnames(F);
 F          = struct2cell(F);
 % Check functions.
 ind = ~cellfun(@(x)isa(x,'function_handle'),F);
 if any(ind)
  if ~all(cellfun(@ischar,F(ind)))
   error('CVARGAS:func2func:invalidStructureFunctionChar',...
    ['Elements of structure function must be either function handles, ' ...
     'name or anonymous definition string.'])
  end
  F(ind) = cellfun(@str2func2,F(ind),'UniformOutput',false);
 end
elseif ischar(F)
 type = 'function_handle';
 F    = {str2func2(F)};
else
 error('CVARGAS:func2func:invalidFunctionType',...
  ['Function input must be either a function handle, name or an ' ...
   'anonymous function definition as a single input or in a cell or ' ...
   'structure of functions.'])
end

function F = str2func2(F)
% My STR2FUNC that works with anonymous functions.
if strcmp(F(1),'@')
 try
  F = eval(F);
 catch
  error('CVARGAS:func2func:invalidCharFunctionAnonymous',...
    ['Incorrect anonymous function string definition "' F '".'])
 end
else
 try
  F = str2func(F);
 catch
  error('CVARGAS:func2func:invalidCharFunctionName',...
    ['Unknown function name "' F '".'])
 end
end

function [ws,forceWs,uWs] = parseVarargin(ws,forceWs,varargin)
% Parse varargin.
% Checks WS input.
if ~isempty(varargin) && ischar(varargin{1}) && ...
  (strcmpi(varargin{1},'base') || strcmpi(varargin{1},'caller'))
 ws          = lower(varargin{1});
 forceWs     = true;
 varargin(1) = [];
end
% Forces to use the workspace?
if isempty(varargin)
 forceWs = true;
end 
% Checks variable inputs.
if ~isempty(varargin) && isstruct(varargin{1})
 % Structure input.
 uWs = varargin{1};
 if length(varargin)>1
  warning('CVARGAS:func2func:ignoredInputs',...
   'Ignored extra inputs after variable structure.')
 end
else
 % Paired inputs.
 try
  uWs = cell2struct(varargin(2:2:end),varargin(1:2:end),2);
 catch
  error('CVARGAS:func2func:incorrectPairedInputs',...
   'Extra inputs must be paired variable name (string) and value.')
 end
end


% [EOF]   func2func.m

Contact us