Redian新闻
>
FP的大神,帮忙看看8行代码是如何打印出x_n的?
avatar
FP的大神,帮忙看看8行代码是如何打印出x_n的?# Programming - 葵花宝典
m*r
1
民科, 正在自学R里面的FP. 原始代码如下(http://adv-r.had.co.nz/Function-operators.html), 说是可以打印出uniroot每次iteration x_n的值。 反正我是看不懂, 为方便讨论, 现在我把代码简化如下:
g show_x ignore tee function(...) {
on_input(...)
f(...) } }
zero R里面运行以上代码,得到以下正确输出
-5.00000000
+5.00000000
+0.50000000
+0.49993896
+0.50000000
可我完全不理解以上8行是怎么工作的。 uniroot是R里面求根的函数。 不管是用简单
的牛顿法,相信大家都学过,还是用别的方法,不是要讨论的问题。 我的问题是:
里面的循环是怎么实现的?
这个tee函数是如何'看到'x_n的?
avatar
d*c
2
tee修改了g,现在tee修改后的函数是uniroot的输入函数,每次被调用的时候都会打印
其输入值. uniroot本身就是把那个输入函数一次次用不同的值迭代
hadley写的太过通用,要搞成一个修改函数的函数,实际上他做的只是这个
g2 cat(x, "\n")
cos(x) - x
}
uniroot(g2, c(-5, 5))
> uniroot(g2, c(-5, 5))
-5
5
0.2836622
0.8752034
0.7229804
0.7386309
0.7390853
0.7390243
0.7390853
$root
[1] 0.7390853
$f.root
[1] -2.603993e-07
$iter
[1] 6
$init.it
[1] NA
$estim.prec
[1] 6.103516e-05
这个总容易看懂了吧
avatar
d*c
3
然后你如果要经常这么用,不想每次都修改g,或者g是个外部函数你不能直接修改代码
,那么就用tee了。
avatar
m*r
4
果然是fp的大神, 佩服。
不过我还有些似懂非懂。 我原先的设想是,按照牛顿法,想把x_n --> x_n+1,就要按
照切线方向移动一段距离, 这段距离就是f/f' 这个没什么说的。如果你输入的g是个
简单函数,比如cos(x) - x或者5x +6, R要么像matlab一样做符号计算(matlab有个
toolbox, 你给他一个什么函数,他都能给你求导), 要么用别的方法求导数, 反正
能算出个f', 然后就可以迭代了。
如果你给出g2 cat(x, 'n')
cos(x) -x
}
R运行的时候,究竟怎么看这个g2 ? 他怎么知道第一行是打印? 第二行是要求根的表
达式(函数)? 为什么第一行不能是你要求根的表达式?? 而且在以后的迭代中, R还能
‘记住’第一行和第二行分别是干什么的。
我是写惯了for loop, 看R竟然如此智能,很惊讶。

【在 d******c 的大作中提到】
: tee修改了g,现在tee修改后的函数是uniroot的输入函数,每次被调用的时候都会打印
: 其输入值. uniroot本身就是把那个输入函数一次次用不同的值迭代
: hadley写的太过通用,要搞成一个修改函数的函数,实际上他做的只是这个
: g2 : cat(x, "\n")
: cos(x) - x
: }
: uniroot(g2, c(-5, 5))
: > uniroot(g2, c(-5, 5))
: -5

avatar
d*c
5
只要g2能有返回值就可以,前面的无所谓
你这个问题实际是uniroot怎么实现,那应该去看uniroot文档。它需要的只是一个函数
,给输入后有输出就是了。这是数值计算,不是符号计算,也不是求导。看看uniroot
帮助就知道,不要瞎猜

【在 m******r 的大作中提到】
: 果然是fp的大神, 佩服。
: 不过我还有些似懂非懂。 我原先的设想是,按照牛顿法,想把x_n --> x_n+1,就要按
: 照切线方向移动一段距离, 这段距离就是f/f' 这个没什么说的。如果你输入的g是个
: 简单函数,比如cos(x) - x或者5x +6, R要么像matlab一样做符号计算(matlab有个
: toolbox, 你给他一个什么函数,他都能给你求导), 要么用别的方法求导数, 反正
: 能算出个f', 然后就可以迭代了。
: 如果你给出g2 : cat(x, 'n')
: cos(x) -x
: }

avatar
m*r
6
大神再看看下面这13行, 这是干嘛呢?
remember memory f memory <# invisible()
}
structure(f, class = "remember")
}
locs vals zero 以上代码的功能是把uniroot每次迭代的输入,输出保存到locs和vals里。
locs 和 vals既是函数,又是对象;既是S3 又是 ‘remember‘
不过locs和val是怎么保存迭代中间结果的, 我就一头雾水了, 虽说里面有个append,
可是它不需要任何参数吗? append把中间结果x, 或者y保存到memory里面, 我看应
该有个参数才对。

uniroot

【在 d******c 的大作中提到】
: 只要g2能有返回值就可以,前面的无所谓
: 你这个问题实际是uniroot怎么实现,那应该去看uniroot文档。它需要的只是一个函数
: ,给输入后有输出就是了。这是数值计算,不是符号计算,也不是求导。看看uniroot
: 帮助就知道,不要瞎猜

avatar
d*c
7
你是跳着看advancedR的吗?前面应该有提到...的特殊作用,那代表所有参数。
remember里面的f有...,所有f的参数都被append到memory了
locs, vals是两个remember函数实例(或者说不同copy),都能记录自己的输入参数到
属于自己的memory。

【在 m******r 的大作中提到】
: 大神再看看下面这13行, 这是干嘛呢?
: remember : memory : f : memory <: # invisible()
: }
: structure(f, class = "remember")
: }
: locs
avatar
m*r
8
果然是这么回事。 在closures/function factories讲到了。 不过我仔细对比了一下
。如果在定义remember的时候,去掉 最后一句话 structure(f, class = "remember"
) , 这个比较好理解。
无非是说,
1. remember是‘function factory’, 是parent function
2. vals 其功能是把所有参数(...)放进memory。 <我的问题是: 这句 structure(f, class = "remember") 是干嘛用的 ? 我知道这句话
叫constructor, 创造出一个对象,该对象属于remember类。可是我要的功能无非把'环
境'里的参数存储到memory里面, 这个过程不需要什么‘对象’.

【在 d******c 的大作中提到】
: 你是跳着看advancedR的吗?前面应该有提到...的特殊作用,那代表所有参数。
: remember里面的f有...,所有f的参数都被append到memory了
: locs, vals是两个remember函数实例(或者说不同copy),都能记录自己的输入参数到
: 属于自己的memory。

avatar
d*c
9
原文里说了
The small amount of S3 code needed is explained in S3.
as.list.remember print.remember 这些你都忽略了?把remember返回值弄成S3,然后可以使用R的method dispatch,当as
.list()遇到一个remember类时,会自动调用as.list.remember,因为你的remember结
构不能直接用通用的as.list,而需要自己定义。这样定义了之后可以在形式上继续使
用通用的as.list。
所以R里你可以plot各种对象,根据对象的类不同调用不同的具体plot函数
你得仔细读,注意细节,前后读完了再回来读。每句话都有原因,提到S3了就要知道那
是干什么的,代码里有...就得知道...是什么,不能忽略过去然后你当然就搞不明白。

remember"

【在 m******r 的大作中提到】
: 果然是这么回事。 在closures/function factories讲到了。 不过我仔细对比了一下
: 。如果在定义remember的时候,去掉 最后一句话 structure(f, class = "remember"
: ) , 这个比较好理解。
: 无非是说,
: 1. remember是‘function factory’, 是parent function
: 2. vals : 其功能是把所有参数(...)放进memory。 <: 我的问题是: 这句 structure(f, class = "remember") 是干嘛用的 ? 我知道这句话
: 叫constructor, 创造出一个对象,该对象属于remember类。可是我要的功能无非把'环
: 境'里的参数存储到memory里面, 这个过程不需要什么‘对象’.

avatar
m*r
10
是啊, 这么简单的事,咋就没想到呢。
经大神提醒我把看不懂的地方都删了
remember memory f memory <}
}
求根完毕之后
unlist(environment(locs)$memory)
unlist(environment(vals)$memory)
就能显示中间每一步结果,避免了面向对象,dispatch,等等复杂的东西。
adv_r 这本书写的不错,就是有点绕来绕去。 比如我想知道closure的定义, hadley
绕啊绕啊和我兜圈子
“An object is data with functions. A closure is a function with data.” —
John D. Cook
One use of anonymous functions is to create small functions that are not
worth naming. Another important use is to create closures, functions written
by functions. Closures get their name because they enclose the environment
of the parent function and can access all its variables. This is useful
because it allows us to have two levels of parameters: a parent level that
controls operation and a child level that does the work.
最后又说,R里面每个函数都是closure, 除非primitive function.
依我看closure可以简单定义如下
1.通过别的函数(function factory, mother function)生成
2.所以有自己的环境(environment), 这个环境是它妈生他时就有啦(他妈也可以生别
的孩子,每个孩子有自己的环境).
3.每个环境存着重要数据,可能是他妈给的,也可能他自己产生的,反正很重要。 等
程序执行完了,环境不丢失,数据也不丢失.

as

【在 d******c 的大作中提到】
: 原文里说了
: The small amount of S3 code needed is explained in S3.
: as.list.remember : print.remember : 这些你都忽略了?把remember返回值弄成S3,然后可以使用R的method dispatch,当as
: .list()遇到一个remember类时,会自动调用as.list.remember,因为你的remember结
: 构不能直接用通用的as.list,而需要自己定义。这样定义了之后可以在形式上继续使
: 用通用的as.list。
: 所以R里你可以plot各种对象,根据对象的类不同调用不同的具体plot函数
: 你得仔细读,注意细节,前后读完了再回来读。每句话都有原因,提到S3了就要知道那

相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。