annotate general/funutils/@func/func.m @ 61:eff6bddf82e3 tip

Finally implemented perceptual brightness thing.
author samer
date Sun, 11 Oct 2015 10:20:42 +0100
parents e44f49929e56
children
rev   line source
samer@4 1 classdef func
samer@4 2 properties (GetAccess=private, SetAccess=private)
samer@4 3 fn
samer@4 4 args
samer@4 5 slots
samer@4 6 end
samer@4 7 methods
samer@4 8 % A func is a partially applied function: Any given function can
samer@4 9 % have some arguments bound to some given parameters, producing a
samer@4 10 % new function which needs only the remaining unbound parameters to
samer@4 11 % be supplied. In addition, the order in which parameters supplied
samer@4 12 % in a subsequent invocation are bound to unbound arguments can be
samer@4 13 % controlled using a slot permutation mechanism. Subscripting operation
samer@4 14 % () is overloaded so that function application works in the normal
samer@4 15 % way except when there are no arguments, in which case you must use FEVAL.
samer@4 16 %
samer@4 17 % For example, if linspace is a function such that
samer@4 18 %
samer@4 19 % linspace(a,b,n)
samer@4 20 %
samer@4 21 % returns an array of n values linearly spaced between a and b,
samer@4 22 % then after
samer@4 23 %
samer@4 24 % fromzero=func(@linspace,0)
samer@4 25 %
samer@4 26 % fromzero(b,n) returns n linearly spaced values from 0 to b.
samer@4 27 % The arguments can be permuted, eg,
samer@4 28 %
samer@4 29 % perm(func(@linspace),[3 1 2])
samer@4 30 %
samer@4 31 % returns a function that takes the arguments in the order (n,a,b)
samer@4 32 % instead of (a,b,n). Permutation and binding can be combined, eg
samer@4 33 %
samer@4 34 % countdown=bind(perm(func(@linspace),[3 2 1]),10)
samer@4 35 % countdown(5,50)
samer@4 36 % ans=
samer@4 37 % 50 45 40 35 30 25 20 15 10 5
samer@4 38 %
samer@4 39 % See Also:
samer@4 40 % PERM, BIND, CURRY, FEVAL, BINDAT
samer@4 41 %
samer@4 42 % Internal structure:
samer@4 43 % cfn.fn : an ordinary matlab function handle
samer@4 44 % cfn.args : a cell array with bound arguments filled in in the order
samer@4 45 % that the ordinary function fn expects them. There may be
samer@4 46 % empty slots if the arguments have been permuted (see CFPERM)
samer@4 47 % cfn.slots : List of empty slots in the order that they are intended to be
samer@4 48 % bound when this curried function is evaluated or has more
samer@4 49 % parameters bound. Eg, the first parameter will be bound to
samer@4 50 % to the slots(1)'th argument of the eventual call to cfn.fn
samer@4 51
samer@4 52 % default function is null function
samer@4 53 function c=func(fn,varargin)
samer@4 54
samer@4 55 if nargin<1, fn=@nop; end
samer@4 56 if isa(fn,'func'), c=fn;
samer@4 57 elseif isa(fn,'struct'),
samer@4 58 c.fn=fn.fn;
samer@4 59 c.args=fn.args;
samer@4 60 c.slots=fn.slots;
samer@4 61 else
samer@4 62 c.fn=fn;
samer@4 63 c.args=varargin;
samer@4 64 c.slots=[];
samer@4 65 end
samer@4 66 end
samer@4 67
samer@4 68 % bind - Bind arguments to a func to create partially applied function
samer@4 69 %
samer@4 70 % bind(fn,a1,a2,..)
samer@4 71 % fn is curried function returned by FUNC, BIND or PERM,
samer@4 72 % the given parameters are bound to the free slots of the function
samer@4 73 % and a new curried function is returned.
samer@4 74
samer@4 75 % Matlab 'feature': if ANY of the paremeters
samer@4 76 % to bind are function objects, then this function gets called, even
samer@4 77 % if the first parameter is just an ordinary function pointer.
samer@4 78 function c=bind(c,varargin)
samer@4 79 if isa(c,'function_handle'), c=func(c); end
samer@4 80
samer@4 81 % first, fill available slots in arg list using supplied args
samer@4 82 m=min(length(c.slots),length(varargin));
samer@4 83 c.args(c.slots(1:m))=varargin(1:m);
samer@4 84 c.slots=c.slots(m+1:end); % remove filled slots
samer@4 85 c.args=horzcat(c.args,varargin(m+1:end)); % append any left over args
samer@4 86 end
samer@4 87
samer@4 88 % BINDAT: Bind arguments at specified positions to create partially applied
samer@4 89 % function
samer@4 90 %
samer@4 91 % BIND(cfn,pos,a1,a2,..)
samer@4 92 % If cfn is an ordinary function, the parameters a1, a2 etc
samer@4 93 % are bound at the positions specified in pos(1),pos(2), etc.
samer@4 94 % Otherwise, the same as BIND.
samer@4 95 %
samer@4 96 % See BIND
samer@4 97
samer@4 98 % need to make sure pos is a complete permutation before
samer@4 99 % calling perm
samer@4 100 function c=bindat(c,pos,varargin)
samer@4 101 pos=[pos setdiff(1:max(pos),pos)];
samer@4 102 c=bind(perm(c,pos),varargin{:});
samer@4 103 end
samer@4 104
samer@4 105 % DISPLAY - Display FUNC object as string
samer@4 106 function display(c), disp([tostring(c),sprintf(' :: func(%d->%d)',nargin(c),nargout(c))]); end
samer@4 107
samer@4 108 % FEVAL: Evaluate partially applied function
samer@4 109 %
samer@4 110 % FEVAL(cfn,a1,a2,...)
samer@4 111 % The given parameters a1, a2, etc. are bound to the arguments of cfn,
samer@4 112 % and eventually to the arguments of a matlab function, possibly
samer@4 113 % permuted according to cfn.slots (see CFPERM)
samer@4 114 function varargout=feval(c,varargin)
samer@4 115 % first, fill available slots in arg list using supplied args
samer@4 116 if ~isa(c,'func'),
samer@4 117 [varargout{1:max(1,nargout)}] = builtin('feval',c,varargin{:});
samer@4 118 return;
samer@4 119 % error('This shouldn''t be happening!');
samer@4 120 end
samer@4 121 m=min(length(c.slots),length(varargin));
samer@4 122 args=c.args;
samer@4 123 args(c.slots(1:m))=varargin(1:m);
samer@4 124
samer@4 125 % append any left over args
samer@4 126 if nargout==0, c.fn(args{:},varargin{m+1:end});
samer@4 127 else [varargout{1:max(1,nargout)}] = c.fn(args{:},varargin{m+1:end});
samer@4 128 end
samer@4 129 end
samer@4 130
samer@4 131
samer@4 132 % GETARG - Extract a bound argument from a FUNC object
samer@4 133 % getarg :: (func (D1,...,Dn)->R, k:natural) -> Dk
samer@4 134 function a=getarg(c,n), a=c.args{n}; end
samer@4 135
samer@4 136 % GETFN - Get ordinary function handle from FUNC object
samer@4 137 function fn=getfn(c), fn=c.fn; end
samer@4 138
samer@4 139 % PERM: permute arguments to a curried function
samer@4 140 % PERM(cfn,perm)
samer@4 141 % cfn can be an ordinary function handle or a curried function as returned
samer@4 142 % by BIND or PERM.
samer@4 143 %
samer@4 144 % The 1st argument of PERM(F,P) will bind to the P(1)'th argument of F.
samer@4 145 % Sequential permutations compose properly.
samer@4 146 % P must be a complete permutation: if length(P)=L, then P must
samer@4 147 % contain each of the intergers 1 to P exactly once.
samer@4 148 % The binding order of arguments after the Lth is not affected.
samer@4 149 function c=perm(c,slots)
samer@4 150 m=length(c.slots);
samer@4 151 n=length(slots);
samer@4 152 l=length(c.args);
samer@4 153 if m<n, c.slots=[c.slots l+1:l+n-m];
samer@4 154 elseif m>n, slots=[slots n+1:m]; end
samer@4 155 c.slots=c.slots(slots);
samer@4 156 end
samer@4 157
samer@4 158 function varargout=subsref(c,S)
samer@4 159 % SUBSREF - Subscript referencing for FUNC objects
samer@4 160 %
samer@4 161 % f(a,b,c)=feval(f,a,b,c) - parenthesis subsref invokes the function
samer@4 162 % f{a,b,c}=bind(f,a,b,c) - braces subsref binds more arguments
samer@4 163
samer@4 164
samer@4 165 s=S(1);
samer@4 166 switch s.type
samer@4 167 case '()'
samer@4 168 % first, fill available slots in arg list using supplied args
samer@4 169 m=min(length(c.slots),length(s.subs));
samer@4 170 args=c.args;
samer@4 171 args(c.slots(1:m))=s.subs(1:m);
samer@4 172 [varargout{1:nargout}] = c.fn(args{:},s.subs{m+1:end});
samer@4 173 case '{}'
samer@4 174 varargout{1}=bind(c,s.subs{:});
samer@4 175 if length(S)>1,
samer@4 176 [varargout{1:nargout}] = subsref(varargout{1},S(2:end));
samer@4 177 end
samer@4 178 end
samer@4 179 end
samer@4 180
samer@4 181 function str=tostring(c)
samer@4 182 % TOSTRING - Implementation of string conversion for FUNC objects
samer@4 183 %
samer@4 184 % tostring :: func -> string
samer@4 185
samer@4 186 str=[];
samer@4 187 slots=c.slots; m=length(slots);
samer@4 188 args=c.args; l=length(args);
samer@4 189 n=max(slots);
samer@4 190 if l<n, args=[args cell(1,n-l)]; l=n; end;
samer@4 191 for i=1:m
samer@4 192 args{slots(i)}=['#' num2str(i)];
samer@4 193 end
samer@4 194
samer@4 195 for i=1:l
samer@4 196 str=[str tostring(args{i}) ','];
samer@4 197 end
samer@4 198 if n>0, str=[str ' ']; end
samer@4 199 if isa(c.fn,'function_handle') fstr=['@' func2str(c.fn)];
samer@4 200 elseif isa(c.fn,'inline') fstr=['\' char(c.fn) '\'];
samer@4 201 end
samer@4 202 str=[ fstr '(' str '...)'];
samer@4 203 end
samer@4 204 function n=nargout(f), n=nargout(f.fn); end
samer@4 205 function n=nargin(f), n=nargin(f.fn)-length(f.args); end
samer@4 206 end
samer@4 207 end
samer@4 208