[dynamic FL]part 5:基本概念

Racket : 动态语言,而非静态
Racket和Scheme同源,来自LISP。可以讲任何类型的数据放在任何相仿的地方

Racket由一组definition组成,括号用来求值e并调用函数。
     括号内可以有atom: 包含特定值,变量和关键字(define lambda if)。
     所有的东西都是前缀形式,如2+3=>(+ 2 3)
(t1 t2 …):如果t1是关键字:有特殊用处的表达式
                 如果t1不是关键字:函数调用

top-level definitions:ML中的所有binding类似let*,Racket中的definition类似letter。
     注意:1.不能同名
                2.如果前面的binding使用后面的,放在函数里
                3.没有top-level shadowing(不能同名),但是一个模块能shadow另一个文件中的binding

mutate: (set! x e)
     如果调用函数,函数会找某个值在上下文中的最终值,可能是修改后的。如果要使用之前的值,在函数中拷贝一份
     top-level binding不会在其他地方改变,除非定义它的模块显式的set!了
     只改变x指向的对象,不能改变对象的内部。如果对象是list,要改变内部需要用mcons等等改变

lazy evaluation: call-by-need, promise. 使用mutation + list记住最初使用thunk的值,以后就不用再次调用thunk了。
     thunk使用无参数的匿名函数来delay evaluation:Racket中,调用(e1 x y)时,总是会先evaluate x,y然后再进入函数体。然而如果是lambda(…)…,则会在调用的时候才evaluate。这样(e1 (lambda() x) (lambda() y))就不会evaluate x, y了,只有函数体显示调用函数的时候才会evaluate。使用lambda() x替代x
     my-delay是一个函数/数据结构,传入一个thunk f, 如果没有调用过f,则返回(#f, f),如果要调用,则将my-delay改为(#t, f的调用结果)
     
     例子:仅仅使用thunk
     
     call:
     使用force-delay+thunk
     call:
     另一种:
     
     call:

stream:是一个无穷序列
     用thunk表示stream,当调用的时候:生成序列中的一个值,并且返回产生下一个值的thunk


memorization: 使用memo table


macro:(define-syntax x (syntax-rules (rest of x’s key words)
                              [(how to write macro) (macro-expansion)]))
     允许程序员定制自己的语法糖
     macro use:使用宏的地方
     macro define:定义宏
     macro expansion:使用宏定义中的内容替换使用宏的地方。发生在一切之前,在type-checking, compiling...之前
     tokenization:将程序分解成token,因此a->b并不意味着at->bt
     parenthesization:Racket中的宏展开保持了原有的函数结构,宏展开的结果和宏使用都放在一个括号内
     scope:宏展开不适用于变量定义,自带的car等等会shadow同名的宏定义
     只有宏能通过添加thrunk实现evaluation延迟,函数必须传入thunk,因为函数一定会evaluate参数
     
     local variable: 宏中+e e不等于* 2 e,需要使用let将e的值存起来为x,再对x做处理。
     hygiene: 在使用宏的时候,let中虽然传入的可能是一个名为x的自由变量,但是在Racket中会用不同名字表示(rewritten),不会和宏定义中的let [x e]中的x混淆;
                   宏定义中使用的自由变量来自定义宏的时候的上下文,而不是使用宏的上下文。因此不会被使用宏时的自由变量影响

definition: (define x e)
anonymous function: (lambda (x) e)
     (define f (lambda(x) e))
     和ML不同,lambda函数可以使用递归,因为它的定义在函数体的上下文中
currying:
     (define f ((lambda(x) (lambda(y) e)))  或者 (define ((f x) y) e) =>((f x) y)
#t, #f:True, False,除了#f其他都是True
list: 可含有不同类型的元素
       null: 空list
       cons: 创建list(cons 2(cons 3 null))。实际上cons只是创建一个pair,前面的部分能用car访问,后面的部分能用car访问。如果不是接的null,则是pair,也叫作improper list。improper list可以用来创建each-of类型,最好用proper-list创建长度会变化的collection
       car: 获取第一个元素
       cdr: 获取除第一个外的其他元素
       null?: 检查是否是空list
       list: 创建list (list 2 3)
cond: (cond [e1 e2]
                   [e1 e2]...)
     类似switch...case, e1是条件,e2是条件为真时执行的语句
let: (let ([x1 e1]
             [x2 e2]...)
      e)
     使用let之前的环境evaluate ei,e2中不能用x1
let*:使用let之前的环境以及let*中前面的binding evaluate ei,e2可以用x1,但是e1不能用x2,因此不能递归
       和ML的let相同。嵌套的let就是let*
letrec:可以使用同一组let中之前和之后的上下文。通常用于定义相互引用的函数
          注意,虽然可以使用,但是每个binding还是依次evaluate的。相互引用的函数中,可以调用另一个函数并且不会出问题,因为函数没有调用,就不会使用变量,所以在第一个函数中调用没有evaluate的第二个函数没有问题。定义值则有问题。
struct: (struct foo (bar bah) #:transparent)
     foo:类似ML的constructor,在环境中添加 创建foo的函数,参数有两个分别给bar和bah
     foo?: 测试是否是foo的函数
     foo-bar:提取foo的bar的内容的函数
     attribute: #:transparent:允许fields和accessor function在模块外可见
                     #:mutable:允许通过set-foo-bar!来修改fields
     创建一种新的类型的数据结构,能够尽早发现错误,能够隐藏部分接口,使得模块外不可见

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值