Mercurial > hg > ishara
changeset 38:9d24b616bb06
Added function algebra.
author | samer |
---|---|
date | Tue, 29 Jan 2013 15:59:01 +0000 |
parents | beb8a3f4a345 |
children | c388f1c70669 |
files | general/funutils/@function_handle/and.m general/funutils/@function_handle/ctranspose.m general/funutils/@function_handle/ge.m general/funutils/@function_handle/gt.m general/funutils/@function_handle/horzcat.m general/funutils/@function_handle/lt.m general/funutils/@function_handle/mpower.m general/funutils/@function_handle/mrdivide.m general/funutils/@function_handle/not.m general/funutils/@function_handle/or.m general/funutils/@function_handle/power.m general/funutils/@function_handle/private/acount.m general/funutils/@function_handle/rdivide.m general/funutils/@function_handle/table.m general/funutils/@function_handle/vertcat.m general/funutils/README.txt general/funutils/TODO general/funutils/funseq.m general/funutils/multicall.m sequences/+seq/selector.m |
diffstat | 20 files changed, 261 insertions(+), 41 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/and.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,23 @@ +% and - function combinator, f&g (...) = f(...); return g(...) +% +% and :: +% (A{:} => B{:}), +% (A{:} => C{:}) +% -> (A{:} => C{:}). +% +% and :: +% (A{1:N} => B{:}), +% (A{1:N} => C{1:M}), +% N:natural, +% M:natural +% -> (A{1:N} => C{1:M}). +function h=and(f,g,nin,nout) + if nargin<4, nout=nargout(g); end + if nargin<3, nin=nargin(g); end + fns = { @q11, @q1n; @qn1, @qnn }; + h=fns{acount(nin,1),acount(nout,1)}; + function y=q11(x), f(x); y=g(x); end + function y=qn1(varargin), f(varargin{:}); y=g(varargin{:}); end + function varargout=q1n(x), f(x); [varargout{1:nargout}]=g(x); end + function varargout=qnn(varargin), f(varargin{:}); [varargout{1:nargout}]=g(varargin{:}); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/ctranspose.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,10 @@ +function h=ctranspose(f,nin,nout) + fns = { @q21, @q2n; @qn1, @qnn }; + if nargin<3, nout=nargout(f); end + if nargin<2, nin=nargin(f); end + h=fns{acount(nin,2)-1,acount(nout,1)}; + function y=q21(x,y), y=f(y,x); end + function y=qn1(x,y,varargin), y=f(y,x,varargin{:}); end + function varargout=q2n(x,y), [varargout{1:nargout}]=f(y,x); end + function varargout=qnn(x,y,varargin), [varargout{1:nargout}]=f(y,x,varargin{:}); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/ge.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,7 @@ +function g=ge(f,nout) + if nargin<2, nout=nargout(f); end + if nout<0, error('function must have a definite number of outputs'); end + if nargin(f)==1, g=@h1; else g=@hn; end + function rets=h1(x), [rets{1:nout}]=f(x); end + function rets=hn(varargin), [rets{1:nout}]=f(varargin{:}); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/gt.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,12 @@ +function g=gt(f,I,nin) + if nargin<3, nin=nargin(f); end + nout=length(I); MI=max(I); + fns = { @q11, @q1n; @qn1, @qnn }; + g=fns{acount(nin,1),acount(nout,1)}; + + function y=q11(x), [rets{1:MI}]=f(x); y=rets{I}; end + function y=qn1(varargin), [rets{1:MI}]=f(varargin{:}); y=rets{I}; end + function varargout=q1n(x), [rets{1:MI}]=f(x); varargout=rets(I); end + function varargout=qnn(varargin), [rets{1:MI}]=f(varargin{:}); varargout=rets(I); end +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/horzcat.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,32 @@ +% horzcat - function combinator, +% +% horzcat :: +% F:(A{1:N} => B{1:M}), +% G:(A{1:N} => C{1:L}), +% N:natural, ~'defaults to nargin(F)' +% M:natural ~'defaults to nargout(F)' +% -> (A{1:N} => B{1:M}, C{1:L}). +function h=horzcat(varargin) + funs=varargin; + nouts=cell2mat(map(@nargout,varargin)); + NN=sum(nouts); N=length(funs); + fns = { @q1n; @qnn }; + h=fns{acount(nargin(funs{1}),1)}; + + function varargout=q1n(x), + varargout=cell(1,NN); + j=0; for i=1:N + k=j+nouts(i); + [varargout{j+1:k}]=funs{i}(x); + j=k; + end + end + function varargout=qnn(varargin), + varargout=cell(1,NN); + j=0; for i=1:N + k=j+nouts(i); + [varargout{j+1:k}]=funs{i}(varargin{:}); + j=k; + end + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/lt.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,10 @@ +function g=le(f,I) + if nargout(f)==1, g=@q1; else g=@qn; end + + function x=q1(varargin) + x=f(varargin{I}); + end + function varargout=qn(varargin) + [varargout{1:nargout}]=f(varargin{I}); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/mpower.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,3 @@ +function varargout=mpower(f,x) + [varargout{1:nargout}]=f(x); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/mrdivide.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,11 @@ +% lt - Bind one argument to a function using Matlab closure +% +% lt :: +% (A{1:N}->B{1:L}) ~'func from N inputs to L outputs', +% A{1} ~'first argument' +% -> (A{2:N}->B{1:L}) ~'func from remaining arguments to returns'. + +function g=lt(f,x) + g=@(varargin)f(x,varargin{:}); +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/not.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,7 @@ +function g=not(f,nout) + if nargin<2, nout=nargout(f); end + if nout<0, error('function must have a definite number of outputs'); end + if nargin(f)==1, g=@h1; else g=@hn; end + function rets=h1(x), [rets{1:nout}]=f(x); end + function rets=hn(varargin), [rets{1:nout}]=f(varargin{:}); end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/or.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,22 @@ +% or - function combinator, f|g (...) = f(...), g(...) +% +% or :: +% F:(A{1:N} => B{1:M}), +% G:(A{1:N} => C{1:L}), +% N:natural, ~'defaults to nargin(F)' +% M:natural ~'defaults to nargout(F)' +% -> (A{1:N} => B{1:M}, C{1:L}). +function h=and(f,g,nin,nout) + if nargin<4, nout=nargout(f); end + if nargin<3, nin=nargin(f); end + fns = { @q11, @q1n; @qn1, @qnn }; + h=fns{acount(nin,1),max(acount(nargout(g),1),acount(nout,1))}; + + function [y,z]=q11(x), y=f(x); z=g(x); end + function [y,z]=qn1(varargin), y=f(varargin{:}); z=g(varargin{:}); end + function varargout=q1n(x), [varargout{1:nout}]=f(x); [varargout{nout+1:nargout}]=g(x); end + function varargout=qnn(varargin), + [varargin{1:nout}]=f(varargin{:}); + [varargout{1:nargout}]=g(varargin{:}); + end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/power.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,2 @@ +function varargout=lt(f,args) + [varargout{1:nargout}]=f(args{:});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/private/acount.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,1 @@ +function n=acount(m,k), if m<0 || m>k, n=k+1; else n=m; end; end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/rdivide.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,11 @@ +% rdivide - Bind arguments to a function using Matlab closure +% +% rdivide :: +% func(A{1}, ..., A{N}->B{1:L}) ~'func from N inputs to L outputs', +% A{1}, ..., A{M} ~'M<=N input arguments of the correct types' +% -> func(A{M+1}, ..., A{N}->B{1:L}) ~'func from remaining arguments to returns'. + +function g=rdivide(f,args) + g=@(varargin)f(args{:},varargin{:}); +end +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/table.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,39 @@ +function [g,s,l,seq]=table(f,varargin) + opts=options('nargin',nargin(f),'nargout',nargout(f),'file',[],varargin{:}); + nin=opts.nargin; + nout=opts.nargout; + + Table=cell(0,nin+nout); + + g=@lookup; + s=@saver; + l=@loader; + seq=@getrows; + + function s=getrows, s=slices(Table,1); end + function saver(file), + if nargin<1, file=opts.file; end + fprintf('saving %d tabled rows of %s to %s\n',size(Table,1),tostring(f),file); + d.table=Table; + save(file,'-struct','d'); + end + function loader(file), + if nargin<1, file=opts.file; end + d=load(file); + Table=d.table; + fprintf('loading %d tabled rows of %s from %s\n',size(Table,1),tostring(f),file); + end + + function varargout=lookup(varargin) + matches=select(@(r)isequal(varargin,r(1:nin)),slices(Table,1)); + if isempty(matches) + [varargout{1:nout}]=f(varargin{:}); + Table=vertcat(Table,[varargin,varargout]); + else + varargout=col(head(matches),nin+(1:nout)); + end + end +end + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/@function_handle/vertcat.m Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,27 @@ +% vercat - function combinator, f&g (...) = f(...); return g(...) +% +% and :: +% (A{:} => B{:}), +% (A{:} => C{:}) +% -> (A{:} => C{:}). +% +% and :: +% (A{1:N} => B{:}), +% (A{1:N} => C{1:M}), +% N:natural, +% M:natural +% -> (A{1:N} => C{1:M}). +function h=vercat(varargin) + g=varargin{end}; + N=length(varargin)-1; + fx=varargin(1:N); + fns = { @q11, @q1n; @qn1, @qnn }; + h=fns{acount(nargin(g),1),acount(nargout(g),1)}; + function y=q11(x), callfx1(x); y=g(x); end + function y=qn1(varargin), callfxn(varargin); y=g(varargin{:}); end + function varargout=q1n(x), callfx1(x); [varargout{1:nargout}]=g(x); end + function varargout=qnn(varargin), callfxn(varargin); [varargout{1:nargout}]=g(varargin{:}); end + + function callfx1(x), for i=1:N, fx{i}(x); end; end + function callfxn(args), for i=1:N, fx{i}(args{:}); end; end +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/general/funutils/README.txt Tue Jan 29 15:59:01 2013 +0000 @@ -0,0 +1,42 @@ +This directory contains some tools to enable a more functional style of programming. + + +The methods in the directory @function_handle apply to ordinary Matlab function +handles and implement an algebra of functions accessed via Matlab's numerical +and logical operators which are normally inapplicable to function handles. + + + plus - call two functions in parallel distributing ins and collecting outs + * mtimes - function composition + & and - call two functions and return value from 2nd + | or - call two functions and return values from both + [,] horzcat - sequence calls and collect all returns + [;] vertcat - sequence calls and return last + ^ mpower - unary application + .^ power - application to cell array of arguments + / rdivide - bind (unary partial application) + ./ mrdivide - unary application (bind and call) [!!! cell input?] + > gt - select output args + >= ge - collect N output args in cell + < lt - select input args + <= le - select input args from cell array + ~ not - collect all output args to cell + ' ctranspose - flip 1st and 2nd args + + [f1,f2,...,fn] == f1|f2|...|fn + [f1;f2;...;fn] == f1&f2&...&fn + f/x/y^z == f.^{x,y,z} + + + Unused operators: \ .\ .* + + +Old functions (some not functional algebraic) + + bind1 - partial application, arbitrary arity + flip + apply + compose + + doreturn(f,x,y,...) == feval([f<[];@deal],x,y,...) + nthret(I,f,x,y,...) == feval(f>I,x,y,...) + returns(N,f,x,y,...) == feval(f>I>=max(I), x,y, ...)
--- a/general/funutils/TODO Mon Jan 28 10:52:11 2013 +0000 +++ b/general/funutils/TODO Tue Jan 29 15:59:01 2013 +0000 @@ -1,4 +1,4 @@ -Think about algebra of function handles - funseq, scanner_add_plotter etc +Think about algebra of function handles - scanner_add_plotter etc are special cases function combinators. What is the most general language for function algebra? Is it the arrow algebra restricted to functional arrows?
--- a/general/funutils/funseq.m Mon Jan 28 10:52:11 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -function h=funseq(varargin) -% funseq - Constructs sequential application of several functions -% -% h=funseq(f,...,g) -% -% returns the function h such that h(...) = g(...) but -% all functions are evaluated in order. - - fns=varargin; - h=@seq; - - function varargout=seq(varargin) - for i=1:length(fns)-1 - feval(fns{i},varargin{:}); - end - if nargout==0, - feval(fns{end},varargin{:}); - else - [varargout{1:nargout}]=feval(fns{end},varargin{:}); - end - end -end
--- a/general/funutils/multicall.m Mon Jan 28 10:52:11 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,17 +0,0 @@ -function varargout=multicall(varargin) -% multicall - sequential call to several closures, return values from last -% -% y=do(f,g,...,h,x) -% -% equivalent to -% f(x); g(x); ...; y=h(x); - - for i=1:length(varargin)-1 - feval(varargin{i}); - end - if nargout==0, - feval(varargin{end}); - else - [varargout{1:nargout}]=feval(varargin{end}); - end -end
--- a/sequences/+seq/selector.m Mon Jan 28 10:52:11 2013 +0000 +++ b/sequences/+seq/selector.m Tue Jan 29 15:59:01 2013 +0000 @@ -10,7 +10,7 @@ methods (Static) function o=make(fn,source) source=dropwhile(inverse(fn),source); - if isempty(source), o=nil; else o=seq.selector(fn,source); + if isempty(source), o=nil; else o=seq.selector(fn,source); end end end methods