我: 你知道惰性求值么
2:09
另一个人: IEnumerable的yield return?
我: 额 那个也是
我不知道yield的机理
2:10
惰性求值有2个关键
1个是延迟到第一次使用的时候才求值,
2是第二次用到的时候直接把上次算过得结果返回,也就是缓存。
2:11
这样能减少大量的计算和时间
另一个人: 嗯。。那用属性也是容易做到的
单个值的话
我: 恩 oop的语言是最容易做到的
另一个人: 如果多个值就用yield return了
我: scheme里面是用delay 和force两个关键字做到的
2:12
另一个人: c# 4.0貌似有多了一个lazy的东西。。
是干这个的
我: 额 我现在用yield的地方都没一个 真汗
2:13
另一个人: 呵呵,可以用yield return构造一个list,但我不确定它是不是只被调用一次
2:14
IEnumberable Numbers{}
我: 你这样的话是用来遍历的吧?
如果是随机读取容器中的一个要怎样做到?
2:15
另一个人: IEnumberable Numbers{
get{
yield return 1;
yield return 2;
}
}
我: 这样是有顺序的吧
另一个人: 嗯。。那应该只能自己实现了。。
2:16
我: 我感觉用yield return的话就只能按顺序取出来使用
另一个人: 对
我: 并且用完了就没得用了?
2:17
另一个人: 那你可以在它用的时候copy一份到list里面
第二次就取list的
2:18
我: IEnumberable
是个什么东西?
不是容器吧
另一个人: 多打了个b。。
IEnumerable
2:19
我: 这样需要外部去copy一个混存
有没办法内部封装下
外部没感觉呢
另一个人: 嗯,当然可以封装啊
2:20
我: 我这几天看一本好书
叫冒号课堂
讲各种各样的范式 模式 很好玩
2:21
另一个人: 好像有看过这个博客。。不知道是不是同一个人
我: 还有一种语言类型叫逻辑式
另一个人: 用讲故事的方式,对吗?
我: Prolog
恩 一条条断言
另一个人: 嗯,这个我们学人工智能的时候学过。。。
我: 很有意思
2:22
另一个人: 不过挺难的。。
我: 它关注的不是命令 也不是函数 而是关系
另一个人: 嗯
我: 额 我感觉如果习惯了那种思维写起来很爽
2:23
另一个人: 嗯,做复杂逻辑很方便。。。
我: 跟数学表达式几乎没什么区别。。。
哈哈
另一个人: 当时好像我们老师写了一下那个经典的坐船过河的。。就几行。。
我: quiksort 它也就几行搞定。。
2:24
另一个人: 呵呵
我: 呵呵 不过效率可能跟函数式差不多
因为是解释的吧?
对了 说函数式语言是无状态的
我感觉不怎么好理解
2:25
什么叫无状态
2:26
另一个人: 我也说不好。。我的理解就是相互之间没有关联,要自己来建立关联
2:27
我: 我的感觉是
函数是没有状态的
2:28
也就是函数是可重入的
如果c里面的函数都写成可重入的话
另一个人: 嗯
我: 那就是也具备了无状态的特点
但显然我们在命令式代码里面几乎很少写可重入函数
2:29
不同时刻调用的时候状态不一样
但是我感觉,函数式语言里面的变量应该是有状态的吧?
2:30
另一个人: 嗯,函数就是依靠变量来控制状态的。。
我: 那就奇怪了
2:31
如果它的函数使用了外部变量 不就具有状态了么?
另一个人: 得使用全局变量,才能说它是有状态的
2:32
我: 恩 局部变量是没有 额 是这样理解的么,我感觉它也会使用全局变量的
http://blog.upsuper.org/erlang-implementation-of-0-1-knapsack-algorithm/
看这个Erlang语言 好难理解
2:33
另一个人: 好晕。。
2:36
我: Erlang因为是函数语言 没有状态 所以可以大量使用并行 很牛逼
Unix的管道思想也是这个 但是我还是没理解好状态
2:37
另一个人: 无状态应该就是,这次进来是这样,下次进来还是这样,只跟参数有关,跟时间无关
2:38
我: 那岂不是都不能使用外部变量。。。
2:39
一旦使用外部变量就没法不跟时间无关
另一个人: 是啊
我: 可是
为什么说函数语言里面没有赋值?
2:40
另一个人: 没有赋值?
我: 哦 我理解了
你看
(define a ....)
在定义的时候就被求值了
所以即使其他函数使用a 也跟时间无关
2:41
不管什么地方使用 a 如果是个列表 的话 因为定义的时候就被求值 所以跟世界无关
2:42
然后如果a是个函数 递归的 没有状态 跟时间无关
另一个人: 嗯,被调用的时候要重新做里面的计算
2:43
我: 恩
重新计算的话 如果有用到外部的变量 递归重新计算?
直到(define b 2)这种为止
但是这种显然是时间无关的
另一个人: 嗯
我: 所以整体是时间无关的
呵呵
2:44
另一个人: 嗯
我: 那看来 惰性求值是一种变相打破无状态的工具
另一个人: 应该也不算打破,只是改变其中一些工作方式吧。。
我: (define (delay (f a) ...))
2:45
恩 我感觉惰性求值就具备了状态吧?
不过很微弱的状态
2:46
另一个人: 也没有,这样返回的时候把整个式子返回出来,而不是直接返回结果
我: 因为它第二次调用的话是直接返回上次计算的结果 这明显具备了时间!
额 因为是整个式子
2:47
所以如果要用就一定要 (force f)强迫求值
但是这个关键字是会在第二次调用的时候直接返回上次结果的
另一个人: 嗯,把计算的时间分散开
我: 那就具备了时间性
2:48
计算的时间被延迟到第一次force
额 那如果没有用force岂不是每次都是重新计算?
2:49
没有用delay
另一个人: 嗯。。应该是
如果第二次直接返回上次的结果。。那应该是具备了时间性
2:50
我: 尾递归你还记得么
原始的递归是无状态的 所以每次都要递归入栈到底再出栈计算
这样很低效
2:51
我记得尾递归是每次递归的时候就直接求值
另一个人: 嗯,对
我: 为什么能直接求值
另一个人: 把求值放到递归外面来做
2:52
递归通过参数接受每次的结果
我: 恩 想起来了!
真有意思
另一个人: 不过你上面举的delay的例子
我: 看来要理解函数语言就得一定要理解它的无状态
2:53
另一个人: 如果f带的参数不同,应该要重新force吧?
如果不重新force也会得到上一次的结果吗?
我: 额 我马上实验下
我有drscheme
另一个人: 嘿嘿,好
7 分钟
3:01
我: (define (square x) (delay (* x x)))
(display (force (square 2)))
(newline)
(display (force (square 2)))
(newline)
(display (force (square 3)))
-----------------------------------
4
4
9
额 跟没有用delay有什么区别?
3:02
另一个人: 呃。。你不是说第二次可以不用force吗?
我: 没有啊
不用force它就只是返回表达式
要force才求值
3:03
http://www.ibm.com/developerworks/cn/linux/l-lazyprog.html
另一个人: 噢。。那可能是内部建了个cache之类的吧。。
3:04
我: 恩 应该是类似一个散列表的cache
如果参数已存在就直接返回对应的结果
3:05
跟动态规划的技术一样
另一个人: 嗯,这样的话,因为无状态的函数,传入同样的参数,一定返回同样的结果
还是不违反无状态的原则
我: 恩 很牛
整个语言就是无状态的
另一个人: 嘿嘿
我: 嘿嘿 搞懂了 睡觉去啦 呵呵
3:06
我把我们记录群发吧 也许有人会看 呵呵
另一个人: 嗯,我也要睡啦~~鸡都叫了。。呵呵
阅读(3724) | 评论(0) | 转发(0) |