Chapter 6 More about Functions

Functions in Lua are first-class values with proper lexical scoping.
What does it mean for functions to be “first-class values”? It means that,
in Lua, a function is a value with the same rights as conventional values like
numbers and strings. We can store functions in variables (both global and local)
and in tables, we can pass functions as arguments to and return them from other

functions.

What does it mean for functions to have “lexical scoping”? It means that
functions can access variables of their enclosing functions.1 As we will see
in this chapter, this apparently innocuous property brings great power to the
language, because it allows us to apply in Lua many powerful programming
techniques from the functional-language world..


A somewhat confusing notion in Lua is that functions, like all other values,
are anonymous; they do not have names. When we talk about a function
name, such as print, we are actually talking about a variable that holds that
function.  原来lua里面函数于是没有名称的,,only a variable refer to that function.

shows the point:
a = {p = print}
a.p("Hello World") --> Hello World
print = math.sin -- 'print' now refers to the sine function
a.p(print(1)) --> 0.841470
sin = a.p -- 'sin' now refers to the print function
sin(10, 20) --> 10 20


If functions are values, are there expressions that create functions? Yes. In  fact, the usual way to write a function in Lua, such as
function foo (x) return 2*x end

is just an instance of what we call syntactic sugar; it is simply a pretty way to write the following code:

foo = function (x) return 2*x end  --这种写法真正体现了函数其实也就是一variable ...

print(type(foo))  -- function 可以看到这个变量的类型是function,see below:

Therefore, a function definition is in fact a statement (an assignment, more
specifically) that creates a value of type “function” and assigns it to a variable.
We can see the expression function(x)  body  end as a function constructor, just
as {} is a table constructor. We call the result of such function constructors an
anonymous function.


network = {
{name = "grauna", IP = "210.26.30.34"},
{name = "arraial", IP = "210.26.30.23"},
{name = "lua", IP = "210.26.23.12"},
{name = "derain", IP = "210.26.23.20"},
}
If we want to sort the table by the field name, in reverse alphabetical order, we
just write this:
table.sort(network, function (a,b) return (a.name > b.name) end) --- 也就是说通过传递函数我们告知sort,是需要ascending or descending... 比sort 里面传递另外的参数比如'asc' or 'desc' ,or 1 indicate asc, or 2 indicate desc.


A function that gets another function as an argument, such as sort, is
what we call a higher-order function.remember that
higher-order functions have no special rights; they are a direct consequence of
the ability of Lua to handle functions as first-class values.


In an informal  definition, the derivative of a function f in a point x is the value of
(f(x + d) - f(x))/d when d becomes infinitesimally small. According to this
definition, we can compute an approximation of the derivative as follows:

function derivative (f, delta)   -- 注意这个函数返回的不是导数值,而是导函数,是一个函数,,,
delta = delta or 1e-4
return function (x)
return (f(x + delta) - f(x))/delta --如果不是返回函数 ,x怎么传递进来对吧,print (derivative(math.sin(50))) //50

                                                ---能传递到x里面吗,不行,这个print ,打印的是函数的地址

end
end


Given a function f, the call derivative(f) returns (an approximation of) its   derivative, which is another function:
c = derivative(math.sin) -- 这里call function 了,而不是把derivative 赋给c,,,it return a new fuction, the derivate of sin. that's cos .                                                      如果是赋给c, we thould write c=derivative, no ()
 print(math.cos(5.2), c(5.2))
--> 0.46851667130038 0.46856084325086
print(math.cos(10), c(10))
--> -0.83907152907645 -0.83904432662041



Because functions are first-class values in Lua, we can store them not only
in global variables, but also in local variables and in table fields. As we will see
later, the use of functions in table fields is a key ingredient for some advanced
uses of Lua, such as modules and object-oriented programming.


print(derivative(math.sin)); --it's an address, if you writederivative(math.sin()) --will hit an erro,because math.sin(),will be a function call.

function derivative2(f,x,delta)  --一步到位,,,没返回起导函数而是直接求导
delta=delta or 1e-4;
 return   (f(x+delta)-f(x))/delta;
end;

print(derivative2(math.sin,20))




The damper ,阻尼器,中午出WC 拉门的时候,虽然我用了蛮大力的了,但越到底的时候,门转的越慢,,这个阻力就是damper, 在3D 中调节Camera postion and roation 时候我们就需要这个参数,我们不能一下让Camer 马上就对准我们需要的位置,,,need a damper ...



6.1 Closures

When we write a function enclosed in another function, it has full access to
local variables from the enclosing function; we call this feature lexical scoping.

Lexical scoping, plus  first-class functions, is a powerful concept in a programming language, but many
languages do not support it.


names = {"Peter", "Paul", "Mary"}
grades = {Mary = 10, Paul = 7, Peter = 8}

table.sort(names, function (n1, n2)  --inside  this anomynous function ,  can accessgrades varibel.
return grades[n1] > grades[n2] -- compare the grades,因为Lua treat each chunk as a funciton. so this anomynous     

                                            ----------function is define enclose inside the chunk fucntion

end)


Now, suppose you want to create a function to do this task:
function sortbygrade (names, grades)
table.sort(names, function (n1, n2)  -- 这个anomyous function 也是作为一个闭包传递的
return grades[n1] > grades[n2] -- compare the grades
end)
end

=====上面的那两个示例,恐怕不算lexical scope demo bar, see my  funtion below:

=====2013-12-28 补充

because Lua handles each chunk as a function, a chunk can
declare local functions, which are visible only inside the chunk. Lexical scoping
ensures that other functions in the package can use these local functions:


-------------------------------

function testLexicolScop(a,b)
local x,y=10,11;

function myInsidefunc(c,d)   -- this function define inside the other function,or be enclosed by another function.
  print (a,b,x,y,c,d);
end
return myInsidefunc;  -- Notice, we return a new function ,not to call a function;
end

rf=testLexicolScop(1,3); --call the outside function, and return a new function, notice 我们可以这么看这个return 回来的函数在一个闭包的环境里面,因为他还access outside function's variable. 这个闭包的环境里面就有这些variable.

wen call this function rt,将会在这个环境里面执行,he can access those variable, 就算运行过程中改变了这个闭包环境的变量也不会影响其他的闭包,ie next callrf2=testLexicolScop(4,5);. that's an important understand of Closure function.

rf(13,14);

rf2=testLexicolScop(4,5);
rf2(15,16);


-----anther example of Closure function :


function newCounter ()
  local i = 0
    return function () -- anonymous function
                i = i + 1
               return i
               end
end


c1 = newCounter()
print(c1()) --> 1
print(c1()) --> 2


c2 = newCounter()
print(c2()) --> 1   -- a new closure function env
print(c1()) --> 3
print(c2()) --> 2


Technically speaking, what is a value in Lua is the closure, not the function.
The function itself is just a prototype for closures. Nevertheless, we will continue
to use the term “function” to refer to a closure whenever there is no possibility
for confusion.


Closures are  useful for callback functions, too. A typical example here occurs when you create  buttons in a conventional GUI toolkit. Each button has a callback function  to be called when the user presses the button; you want different buttons to do  slightly different things when pressed. For instance, a digital calculator needs

ten similar buttons, one for each digit. You can create each of them with a function  like this:
function digitButton (digit)
return Button{ label = tostring(digit),  -- Button 也是一个function ,因为只传递一个table,so can ignore ().so here we invoke the Button function,not to return a function
action = function ()
add_to_display(digit) --注意到了吗digit variable 会在这个闭包的env 里面。。。
end
}
end


In this example, we assume that Button is a toolkit function that creates new
buttons; label is the button label; and action is the callback closure to be
called when the button is pressed. The callback can be called a long time after
digitButton did its task and after the local variable digit went out of scope, but
it can still access this variable


Because functions  are stored in regular variables, we can easily redefine functions in Lua, even  predefined functions.
oldSin = math.sin
math.sin = function (x)
return oldSin(x*math.pi/180)
end
A slightly cleaner way to do this redefinition is as follows:
do
local oldSin = math.sin
local k = math.pi/180
math.sin = function (x)
return oldSin(x*k)
end
end

math.sin 就被重定义了,,,接下来的chunk ,调用math.sin 用的就是新的version. oldSin, becuase we define it as

local, so can't be call out side the do end block.

Now, we keep the old version in a private variable; the only way to access it is   through the new version.

You can use this same technique to create secure environments, also called sandboxes. Secure environments are essential when running untrusted code,such as code received through the Internet by a server. For instance, to restrict  the files a program can access, we can redefine the io.open function using  closures:

do
    local oldOpen = io.open
    local access_OK = function (filename, mode)
      <check access>
    end
      io.open = function (filename, mode)
            if access_OK(filename, mode) then
                    return oldOpen(filename, mode)
                 else
                 return nil, "access denied"
                  end
          end
end


after that io.open 多了一个权限测试的功能access_OK

It keeps the insecure version as a private variable in a closure,
inaccessible from the outside. With this technique, you can build Lua sandboxes
in Lua itself, with the usual benefits: simplicity and flexibility.


现在回想javascript also have the same closure feature, also the same meaning...搞了这么多年,终于明白了,,,

所以说还是英文版本的书适合我学习,,,,,


6.2 Non-Global Functions

An obvious consequence of first-class functions is that we can store functions not  only in global variables, but also in table fields and in local variables.
We have already seen several examples of functions in table fields: most Lua
libraries use this mechanism (e.g., io.read, math.sin).

===store function in table fields

Lib = {}
Lib.foo = function (x,y) return x + y end
Lib.goo = function (x,y) return x - y end
print(Lib.foo(2, 3), Lib.goo(2, 3)) --> 5 -1


Of course, we can also use constructors:
Lib = {
foo = function (x,y) return x + y end,
goo = function (x,y) return x - y end
}


Moreover, Lua offers yet another syntax to define such functions:
Lib = {}
function Lib.foo (x,y) return x + y end  --function ,,,end a block
function Lib.goo (x,y) return x - y end


===store function in local varaible

When we store a function into a local variable, we get a local function  Such definitions are particularly
useful for packages: because Lua handles each chunk as a function, a chunk can  declare local functions, which are visible only inside the chunk. Lexical scoping   ensures that other functions in the package can use these local functions:
local f = function (<params>)
<body>
end
local g = function (<params>)
<some code>
f() -- 'f' is visible here  还以为调用不到,,,
<some code>
end


============注意下面的case,不认真测试还发现不出来

local f1=function ()
 myf1localvar="f1";
end

local f2=function()
local  myf2localvar="f2";

end

function f3()
   myf3localvar="f3";
end
function f4()
 local  myf4localvar="f4";
end

print(myf1localvar,myf2localvar,myf3localvar,myf4localvar); --nil     nil     nil     nil

f1();f2();f3();f4();
print(myf1localvar,myf2localvar,myf3localvar,myf4localvar);--f1      nil     f3      nil


还记得我们javascrip function 里面定义变量的时候如果没有加 var 关键字,那么定义的也是global 变量。 同样的道理,而且还有点trick,,看第一次print,如果函数没有执行的话,,,大家都是 nil, 如果执行了函数, 而函数里面定义的变量如果没有加local ,那么函数的执行将会把变量放到了global scope 里面。 同样的,我猜测,如果函数没有定义成local,那么这个函数在这个chunk 里面执行后,将会变成global scope,其他的chunk 也会访问到,看我下面的测试证明了我的猜测:


lession3.lua

if f1 then
print('f1 are defined');
f1();
else
print('f1 are not defined');
end

if f3 then
print('f3 are defined');
f3();
else
print('f3 are not defined');
end


> dofile("lession2.lua");  -- one chunk1
nil     nil     nil     nil
f1 is excuting...   --f1 define as local function to  chunk1
f3 is excuting...  --f3 define as global function, not declare it as local
f1      nil     f3      nil
> dofile("lession3.lua");  --another chunk2
f1 are not defined   -- you can see that f1 is local to chunk1,but we can find f3 in chunk3, so my guess is correct
f3 are defined
f3 is excuting...
>

---我想这也是解析型语言的特点了吧

Lua supports such uses of local functions with a syntactic sugar for them: --还可以这样定义
local function f (<params>)
<body>
end



A subtle point arises in the definition of recursive local functions. The naive  approach does not work here. Consider the next definition:

local fact = function (n)
        if n == 0 then return 1
          else

         return n*fact(n-1) -- buggy
        end
     end


When Lua compiles the call fact(n-1) in the function body, the local fact is not
yet defined. Therefore, this expression will try to call a global fact, not the local
one. local fact = function (n) ... end 这种方式定义的函数,fact 当做一个变量来处理,所以在compile    return n*fact(n-1) ,fact 变量都还没有定义完,所以会抱找不到这个变量的错误,因为global里面也没有,,,


We can solve this problem by first defining the local variable and then the
function:
local fact  -- 这里先吧这个变量定义完先,
fact = function (n)
if n == 0 then return 1
else return n*fact(n-1)
end
end

Now the fact inside the function refers to the local variable.



When Lua expands its syntactic sugar for local functions, it does not use the
naive definition. Instead, a definition like
local function foo (<params>) <body> end
expands to

local foo; foo = function (<params>) <body> end
So, we can use this syntax for recursive functions without worrying.


local function factorial(n)   --所以这方式定义没问题,,所以虽然有两种定义local function 的语法,但还是有区别的
      if n==1 then  return n;
      else
       return n*factorial(n-1);
      end
  end
 
facb=factorial(3)
print(facb);


Of course, this trick does not work if you have indirect recursive functions.
In such cases, you must use the equivalent of an explicit forward declaration:
local f, g -- 'forward' declarations, 不用local function f,g,变量的定义不需要声明
function g ()
<some code> f() <some code>
end
function f ()--不能再写成local function f()...,否则这个f,将会是个fresh local variable f
<some code> g() <some code>
end
Beware not to write local function f in the last definition. Otherwise, Lua
would create a fresh local variable f, leaving the original f (the one that g is
bound to) undefined.


6.3 Proper Tail Calls

Another interesting feature of functions in Lua is that Lua does tail-call elimination.


when a function  calls another as its last action, we call it Tail Call.

function f (x) return g(x) end


below case are not tail call:

function f (x) g(x) end


return g(x) + 1 -- must do the addition
return x or g(x) -- must adjust to 1 result
return (g(x)) -- must adjust to 1 result   -- 上面的4 case 都需要返回来做而外的工作的,so not a tail call.


the program does not  need to return to the calling function when the called function ends. Therefore,
after the tail call, the program does not need to keep any information about  the calling function in the stack. When g returns, control can return directly  to the point that called f.

function f (x)  --pontA

return g(x)  -- pointB

end   也就是g(x) 结束后,不是返回到pointB 点,而是直接返回到pointA, 也就是在call g(x)时候,不需要在开一个stack space 给这个call,否则call 完后应该弹出到stack space start point,that pintB.


function foo (n)
if n > 0 then return foo(n - 1) end
end

It will never overflow the stack.


In Lua, only a call with the form returnfunc(args) is a tail call. However, both
func and its arguments can be complex expressions,
because Lua evaluates them
before the call. For instance, the next call is a tail call:
return x[i].foo(x[j] + a*b, i + j)   --is a tail call.



Exercises
Exercise 6.1: Write a function integral that receives a function f and returns
an approximation of its integral.



Exercise 6.2: Exercise 3.3 asked you to write a function that receives a
polynomial (represented as a table) and a value for its variable, and returns
the polynomial value. Write the curried version of that function. Your function
should receive a polynomial and returns a function that, when called with a
value for x, returns the value of the polynomial for that x. See the example:
f = newpoly({3, 0, 1})
print(f(0)) --> 1
print(f(5)) --> 76
print(f(10)) --> 301



local function newPloynomia(a)
        if type(a)~='table' then
           error ("pls input the table as parameter")
        end;
        
        return function (x)
            sumResult=0;
            for i=1,#a do
              sumResult=sumResult+a[i]*x^(i-1);
            end;
            return sumResult
         end
end

plnew=newPloynomia{5,2,3};
print(plnew(2))




























































































































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《随机信号分析》(Chapter 6)是王永德编写的一本关于随机信号分析的教材,该章节的主要内容是关于信号的功率谱密度函数(PSD)的分析。 在信号处理领域,随机信号是一种在时间和幅度上都是随机变化的信号。对于随机信号的分析,其中一个重要的概念就是功率谱密度函数。功率谱密度函数可以用来描述信号的功率在频域中的分布情况,是信号在不同频率上的功率密度。 在第6章中,王永德首先介绍了图像的基本概念,包括平均值、自相关函数等。然后,他引入了功率谱密度函数的定义,并介绍了如何通过傅里叶变换将信号从时域转换到频域。接着,他详细讲解了如何计算信号在频域上的功率谱密度函数,并给出了一些常见信号的功率谱密度函数的例子。 在随后的内容中,王永德还介绍了如何通过对随机信号的平均值和自相关函数进行估计来估计功率谱密度函数。他解释了如何使用周期图和Welch方法来估计功率谱密度函数,并介绍了这些方法的优缺点。 最后,王永德还介绍了一些关于功率谱密度函数的统计性质,包括自相关函数与功率谱密度函数的傅里叶变换关系以及功率谱密度函数的线性性质等。 总的来说,通过《随机信号分析》(Chapter 6)这一章节的学习,读者可以了解到随机信号分析中功率谱密度函数的基本概念、计算方法及其在信号处理中的应用,为进一步深入学习随机信号分析打下了坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值