• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

Matlab 函数式编程

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

作为一个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

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
matlab 工具函数 —— normalize(归一化数据)发布时间:2022-07-18
下一篇:
Matlab norm 用法小记发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap