matlab 读 函数式,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]), [email protected], @max})

extrema = 1 6

indices = 3 4

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

min_and_max = @(x) cellfun(@(f) f(x), [email protected], @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}, [email protected], @max})

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

map({1, 2}, [email protected], @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 );

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

出现无穷值,报错;

所有值都是0,返回0;

否则,输出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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值