Matlab 函数式编程

作为一个Mathematica的熟练使用者,在切换到Matlab时总会经常产生编程习惯上的“水土不服”。利用Mathematica强大而丰富的内置函数,我们可以以简洁的代码实现复杂的功能。相比之下,Matlab的灵活性就欠缺很多。

为此,本文旨在讨论如何利用Matlab的匿名函数实现类似Mathematica的函数式编程。这里主要使用的是Tucker McClure所编写的函数式编程工具。

Map

下面的代码使用匿名函数同时获取向量中的最大值和最小值:

min_and_max = @(x) [min(x), max(x)];
min_and_max([3 4 1 6 2])
ans =     1     6 

看起来已经足够简洁,但是min和max函数本身可以除了输出最大/小值之外,还可以输出这些值的位置。如果希望使用匿名函数实现上述功能,就需要下面这段代码:

[extrema, indices] = cellfun(@(f) f([3 4 1 6 2]), {@min, @max})
extrema =     1     6
indices =     3     4

上述代码看起来有点奇怪,cellfun作用到了一系列函数句柄上,而不是通常的元素数组,而匿名函数的变量是另一个函数。实际上,我们并不是对数据进行操作,而是在对函数句柄进行操作。上述代码可以进一步构造成下面的形式:

min_and_max = @(x) cellfun(@(f) f(x), {@min, @max});

这样我们就获得了一个强大的新函数,它复合了min和max的功能:

y = randi(10, 1, 10)
just_values        = min_and_max(y)
[~, just_indices]  = min_and_max(y)
[extrema, indices] = min_and_max(y)
y =     9    10     2    10     7     1     3     6    10    10
just_values =     1    10
just_indices =     6     2
extrema =     1    10
indices =     6     2

我们定义的新的min_and_max函数实际上是将基本的min和max函数“map”到了数组上,这正是Mathematica中Map函数的功能。

我们可以更进一步,在Matlab中定义一个通用的Map函数:

map = @(val, fcns) cellfun(@(f) f(val{:}), fcns);

这样,之前的min_and_max函数可以重新写成下面的形式:

x = [3 4 1 6 2];
[extrema, indices] = map({x}, {@min, @max})

这个map函数可以映射多个函数到数组上:

map({1, 2}, {@plus, @minus, @times})
ans =     3    -1     2

如果每个函数的输出大小不相等,可以用下面的mapc函数:

mapc = @(val, fcns) cellfun(@(f) f(val{:}), fcns, ‘UniformOutput‘, false);

mapc({pi}, {@(x) 2 * x, ...                     % Multiply by 2
            @cos, ...                           % Find cosine
            @(x) sprintf(‘x is %.5f...‘, x)})   % Return a string

ans =  1×3 cell 数组
    {[6.2832]}    {[-1]}    {‘x is 3.14159...‘}

这个函数将每个函数的输出合并到一个cell数组中。

正如上面所展示的,这种“作用于函数的函数”正是函数式编程思想的核心所在。

行内条件语句

Matlab的匿名函数并不支持条件语句,但是我们可以通过下面的函数进行变通:

iif = @(varargin) varargin{2 * find([varargin{1:2:end}], 1, ‘first‘)}();

[out1, out2, ...] = iif( if this,      then run this, ...                            else if this, then run this, ...                            ...                            else,         then run this );

这个函数看起来很奇怪,但是使用起来很方便。如果我们要实现下面的判断:

  1. 出现无穷值,报错;
  2. 所有值都是0,返回0;
  3. 否则,输出x/norm(x);

可以用下面的代码实现:

normalize = @(x) iif( ~all(isfinite(x)), @() error(‘Must be finite!‘), ...
                                  all(x == 0),       @() zeros(size(x)), ...
                                  true,              @() x/norm(x) );

normalize([1 1 0])ans =    0.7071    0.7071         0

normalize([0 0 0])ans =     0     0     0

匿名函数的迭代

我们可以定义一个迭代函数,这个函数会调用它自身:

recur = @(f, varargin) f(f, varargin{:});

用这个函数实现斐波那契数列的计算:

fib = @(n) recur(@(f, k) iif(k <= 2, 1, ...
                             true,   @() f(f, k-1) + f(f, k-2)), ...
                 n);

arrayfun(fib, 1:10)ans =     1     1     2     3     5     8    13    21    34    55

计算阶乘:

factorial = @(n) recur(@(f, k) iif(k == 0, 1, ...
                                   true,   @() k * f(f, k-1)), n);
arrayfun(factorial, 1:7)

辅助函数

下面两个辅助函数将小括号和大括号转换为函数形式:

paren = @(x, varargin) x(varargin{:});
curly = @(x, varargin) x{varargin{:}};

这两个函数可以为我们带来很多便利,是我们可以不用定义中间变量就获得想要的值:

magic(3)
paren(magic(3), 1:2, 2:3)
paren(magic(3), 1:2, ‘:‘)

ans =

     8     1     6     3     5     7     4     9     2

ans =

     1     6     5     7

ans =

     8     1     6     3     5     7

curly还有一个作用,就是将几个语句合并到一起:

dots = @() curly({...
    figure(‘Position‘, [0.5*screen_size() - [100 50], 200, 100], ...
           ‘MenuBar‘,  ‘none‘), ...                % Position the figure
    plot(randn(1, 100), randn(1, 100), ‘.‘)}, ...  % Plot random points
    ‘:‘);                                          % Return everything

[h_figure, h_dots] = dots()

更多内容可参考:https://www.mathworks.com/matlabcentral/fileexchange/39735-functional-programming-constructs

原文地址:https://www.cnblogs.com/jerrycetc/p/12389546.html

时间: 2024-10-11 19:36:32

Matlab 函数式编程的相关文章

C语言与MATLAB接口 编程与实例 李传军编着

罗列一下以前自己学习C语言与MATLAB混编的笔记,顺便复习一遍. <C语言与MATLAB接口 编程与实例 李传军编着>(未看完,目前看到P106) 目录P4-8 ****************************************************** C-MEX函数:从MATLAB调用C语言或Fortran语言编写的函数. MEX文件:是一种按一定格式,使用C语言或者FORTRAN语言编写的,由MATLAB解释器自动调用并执行的动态链接函数.在Windows系统中,MEX

Python学习笔记八:文件操作(续),文件编码与解码,函数,递归,函数式编程介绍,高阶函数

文件操作(续) 获得文件句柄位置,f.tell(),从0开始,按字符数计数 f.read(5),读取5个字符 返回文件句柄到某位置,f.seek(0) 文件在编辑过程中改变编码,f.detech() 获取文件编码,f.encoding() 获取文件在内存中的编号,f.fileno() 获取文件终端类型(tty.打印机等),f.isatty() 获取文件名,f.name() 判断文件句柄是否可移动(tty等不可移动),f.seekable() 判断文件是否可读,f.readable() 判断文件是

PYTHON修饰器的函数式编程

转自:http://coolshell.cn/articles/11265.html Python修饰器的函数式编程 Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西.虽然好像,他们要干的事都很相似--都是想要对一个已有的模块做一些"修饰工作",所谓修饰工作就是想给现有的模块加上一些小装饰(一些小功能,这些小功能可能好多模块都会用到),但又不让这个小装饰(小功能

函数式编程

函数式编程 函数式编程的三大特性: immutable data 不可变数据 first class functions 尾递归优化 函数式编程的准则:不依赖于外部的数据,而且也不改变外部数据的值,而是返回一个新的值给你. 如何变得functional: 1. 没有共享变量 2.通过参数和返回值传递数据 3. 函数里没有临时变量 对现有的代码进行重构(refactoring) 使得代码具有functional programming的优点 lambda a, x: x(a) lambda函数可以

Python学习:映射函数(map)和函数式编程工具(filter和reduce)

在序列中映射函数map map函数会对一个序列对象中的每一个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表. 例1: def sum(x):     return x + 10 L1 = [1,2,3,4,5,6,7] L = map(sum, L1) #结果为[11, 12, 13, 14, 15, 16, 17] map还有更高级的使用方法,例如提供了序列作为参数,它能够并行返回分别以每个序列中的元素作为函数对应参数得到的结果的列表.如例2所示. 例2: def sum(

javaScript函数式编程-包含闭包、链式优化及柯里化

本文着重介绍个人理解的函数式编程. 函数式编程个人理解为:以函数为主要载体的编程方式. 好处: 语义更加清晰 可复用性高 可维护性好 作用域局限.副作用少 基本函数式编程: //实现数组中每个单词首字母大写 //一般写法 const arr = ['apple','orange','pear']; for(const i in arr) { const c = arr[i][0]; arr[i] = c.toUpperCase() + arr[i].slice(1); //slice()从已有的

javascript - Underscore 与 函数式编程

<Javascript函数式编程 PDF> # csdn下载地址http://download.csdn.net/detail/tssxm/9713727 Underscore # githubhttps://github.com/jashkenas/underscore # 中文官方网站http://www.css88.com/doc/underscore/ # CDN<script src="https://cdn.bootcss.com/underscore.js/1.8

LUA 函数式编程demo

什么是函数式编程 http://www.zhihu.com/topic/19585411/hot 函数式编程的本质函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射.也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态.比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的.在函数式语言中,函数作为一等公民,可以在任何地方定义,在函数内或函数外,可以作为函数的参数和返回值,可以对函数进行组合.

[Java] 函数式编程相关概念 - 笔记1

Java 8 引入了 lambda 表达式,以及函数式编程风格.在了解函数式编程过程中,做了些笔记,摘录于本文. 嵌套函数( Nested Function ) 1. 嵌套函数,是指在另一个函数里面定义的一个函数.外层的函数,这里简称为外层函数. 2. 函数的嵌套可以是多层嵌套.嵌套函数可以看到其全部的外层函数的非局部变量.在实际程序中,嵌套的层数一般很少.下面是一个三层嵌套的例子, innerOfInner 也可以访问在 outer 函数体重定义的变量 x . function outer()