由买买提看人间百态

boards

本页内容为未名空间相应帖子的节选和存档,一周内的贴子最多显示50字,超过一周显示500字 访问原贴
Programming版 - FP的大神,帮忙看看8行代码是如何打印出x_n的?
相关主题
谁给详细说一下这句有段c++代码看不懂
大过节的,不要吵啦,推荐本函数编程的入门书吧?python比java慢这么多呀
想问个javascript问题,竟然找不到地方数八皇后解法数目:python只要9行
functional programming 哪本书经典适合入门C++ template function type
Java有closure吗?问个disable copy constructor的问题
关于std::vector的一个很简单的问题帮忙看一个code
评估!写多少行程序算多?问一个基本的查找问题
c++ 中如何把str转换为float?二爷说的node beats Ruby其实很清楚啊
相关话题的讨论汇总
话题: function话题: uniroot话题: 函数话题: remember话题: memory
进入Programming版参与讨论
1 (共1页)
m******r
发帖数: 1033
1
民科, 正在自学R里面的FP. 原始代码如下(http://adv-r.had.co.nz/Function-operators.html), 说是可以打印出uniroot每次iteration x_n的值。 反正我是看不懂, 为方便讨论, 现在我把代码简化如下:
g <- function(x) x - .5
show_x <- function(x, ...) cat(sprintf("%+.08f", x), "n")
ignore <- function(...) NULL
tee <- function(f, on_input = ignore, on_output = ignore) {
function(...) {
on_input(...)
f(...) } }
zero <- uniroot(tee(g, on_input = show_x), c(-5, 5));
R里面运行以上代码,得到以下正确输出
-5.00000000
+5.00000000
+0.50000000
+0.49993896
+0.50000000
可我完全不理解以上8行是怎么工作的。 uniroot是R里面求根的函数。 不管是用简单
的牛顿法,相信大家都学过,还是用别的方法,不是要讨论的问题。 我的问题是:
里面的循环是怎么实现的?
这个tee函数是如何'看到'x_n的?
d******c
发帖数: 2407
2
tee修改了g,现在tee修改后的函数是uniroot的输入函数,每次被调用的时候都会打印
其输入值. uniroot本身就是把那个输入函数一次次用不同的值迭代
hadley写的太过通用,要搞成一个修改函数的函数,实际上他做的只是这个
g2 <- function(x) {
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
这个总容易看懂了吧
d******c
发帖数: 2407
3
然后你如果要经常这么用,不想每次都修改g,或者g是个外部函数你不能直接修改代码
,那么就用tee了。
m******r
发帖数: 1033
4
果然是fp的大神, 佩服。
不过我还有些似懂非懂。 我原先的设想是,按照牛顿法,想把x_n --> x_n+1,就要按
照切线方向移动一段距离, 这段距离就是f/f' 这个没什么说的。如果你输入的g是个
简单函数,比如cos(x) - x或者5x +6, R要么像matlab一样做符号计算(matlab有个
toolbox, 你给他一个什么函数,他都能给你求导), 要么用别的方法求导数, 反正
能算出个f', 然后就可以迭代了。
如果你给出g2 <- function(x){
cat(x, 'n')
cos(x) -x
}
R运行的时候,究竟怎么看这个g2 ? 他怎么知道第一行是打印? 第二行是要求根的表
达式(函数)? 为什么第一行不能是你要求根的表达式?? 而且在以后的迭代中, R还能
‘记住’第一行和第二行分别是干什么的。
我是写惯了for loop, 看R竟然如此智能,很惊讶。

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

d******c
发帖数: 2407
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 <- function(x){
: cat(x, 'n')
: cos(x) -x
: }

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

uniroot

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

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

【在 m******r 的大作中提到】
: 大神再看看下面这13行, 这是干嘛呢?
: remember <- function() {
: memory <- list()
: f <- function(...) {
: memory <<- append(memory, list(...))
: # invisible()
: }
: structure(f, class = "remember")
: }
: locs <- remember()

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

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

d******c
发帖数: 2407
9
原文里说了
The small amount of S3 code needed is explained in S3.
as.list.remember <- function
print.remember <- function
这些你都忽略了?把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 <- remember() 创造出了child function(也叫closure?), 有自己的环境,
: 其功能是把所有参数(...)放进memory。 <<-的用法有道理.
: 我的问题是: 这句 structure(f, class = "remember") 是干嘛用的 ? 我知道这句话
: 叫constructor, 创造出一个对象,该对象属于remember类。可是我要的功能无非把'环
: 境'里的参数存储到memory里面, 这个过程不需要什么‘对象’.

m******r
发帖数: 1033
10
是啊, 这么简单的事,咋就没想到呢。
经大神提醒我把看不懂的地方都删了
remember <- function() {
memory <- list()
f <- function(...) {
memory <<- append(memory, list(...))
}
}
求根完毕之后
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 <- function
: print.remember <- function
: 这些你都忽略了?把remember返回值弄成S3,然后可以使用R的method dispatch,当as
: .list()遇到一个remember类时,会自动调用as.list.remember,因为你的remember结
: 构不能直接用通用的as.list,而需要自己定义。这样定义了之后可以在形式上继续使
: 用通用的as.list。
: 所以R里你可以plot各种对象,根据对象的类不同调用不同的具体plot函数
: 你得仔细读,注意细节,前后读完了再回来读。每句话都有原因,提到S3了就要知道那

1 (共1页)
进入Programming版参与讨论
相关主题
二爷说的node beats Ruby其实很清楚啊Java有closure吗?
garbage collecting的语言是不是永远都slow呀关于std::vector的一个很简单的问题
scala for comprehension 不支持 let评估!写多少行程序算多?
FP的好处是不是就是Concurrency?c++ 中如何把str转换为float?
谁给详细说一下这句有段c++代码看不懂
大过节的,不要吵啦,推荐本函数编程的入门书吧?python比java慢这么多呀
想问个javascript问题,竟然找不到地方数八皇后解法数目:python只要9行
functional programming 哪本书经典适合入门C++ template function type
相关话题的讨论汇总
话题: function话题: uniroot话题: 函数话题: remember话题: memory