sicp 笔记 (10)

第四章习题 4.1 – 4.15 的解答。从本章开始使用 mit-scheme 9.1.1。

E-4.1: 题目的意思是,函数 list-of-values 对参数列表的求值顺序依赖于解析器的实现。如果解析器对参数列表的求值顺序是从右往左的,那么 list-of-values 的求值顺序也是从右往左的,也就是说,对于 list-of-values 中的“(cons …)”,会先算“(list-of-values (rest-operands …))”这部分,后算“(eval (first-operand …))”,也就是从右往左了;如果解析器的求值顺序是从左往右,那么 list-of-values 的求值顺序也是从左往右。

(define (list-of-values-lr exps env) ; evaluates from left to right
  (if (no-operands? exps)
    '()
    (let ((first-value (eval (first-operand 

阅读全文…

sicp 笔记 (9)

第三章习题 3.73 – 3.82 的解答。

E-3.73:

(load "../examples/3.5.2-infinite-streams.scm")

(define (integral integrand initial-value dt)
  (define int
    (cons-stream initial-value
                 (add-streams (scale-stream integrand dt)
                              int)))
  int)

(define (RC resistance capacitance time-step)
  (lambda (currents initial-voltage)
    (cons-stream initial-voltage
                 (add-streams (scale-stream currents resistance)
                              (integral (scale-stream currents 

阅读全文…

使用 inotify 监控目录和文件的状态

概述

很多时候程序需要对文件状态进行监控,例如在命令行中删掉一个文件,图形界面中的文件管理器也要把这个文件去掉(如果文件管理器正在显示被删除文件所在的目录);如果试图用 vim 保存一个文件,而该文件在修改的时候被其它程序修改过,那么 vim 会给出警告说文件已经发生改变。如果需要对文件状态进行实时监控,一个方法是保存文件的状态,然后不停地扫描目录或文件,如果和上一次保存的状态不一致则发出信号,但是这样的做法效率很低。最好的做法是能够向系统注册一个回调函数,当我们需要监控的目录或文件发生改变时调用回调函数,这样程序就能马上得到通知。

根据参考资料 [1],inotify 之前的文件状态监控机制是 dnotify。dnotify 中的“d”指的是目录,只能监控目录事件的变化,即在该目录下的创建/删除文件引起的事件,但是却不能监控文件本身状态的改变(如读写/访问文件),如果需要实现这样的功能需要应用程序自己比较文件状态。

在 2.6.13 的时候引入的 inotify 提供了比 dnotify 更强大的功能,除了目录还可以对文件状态进行监控。并且它不像 dnotify,每监控一个目录/文件都需要打开一个文件描述符,因此不会影响移动介质的 unmount。从接口形式和功能上看,inotify 和 epoll 很像,只是两者监控的事件类型不一样。

09 年出现了 fanotify(参考资料 [2]),据说是 inotify 的下一代,不过目前来看功能还不如 inotify。

对目录的监控

作为 inotify 的第一个示例,程序会在 /tmp/abc 被创建/删除/移动时打印相应的信息:

#include <stdio.h>
#include <string.h>

阅读全文…

Thrift 学习笔记 (2)

Google 开发的 Protobuf 会经常被拿来和 Thrift 比较,不过 Protobuf 主要提供序列化/反序列化的功能,而 Thrift 还提供了几个 server 模型,加上可以自动生成代码,大大简化了 RPC 的开发。

TSimpleServer

上一篇笔记 的 echo server 为例,一个使用 TSimpleServer 的服务端如下:

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to 

阅读全文…

Thrift 学习笔记 (1)

Thrift 是 Facebook 开发的一个二进制通信协议,现在托管在 Apache 基金会。它使用一种自定义的接口描述语言描述使用的数据结构和接口,通过编译可以生成各种语言的接口,如 c++,python,php 等。由于支持生成多种语言,Thrift 可以作为多种语言之间的通信接口,更详细的介绍见参考资料 [1]。

这里使用的 Thrift版本是 0.8.0。

一个简单的echo server

首先编写对应的数据结构和接口描述文件:

namespace cpp Test

service EchoServer {
    string echo(1: string msg);
}

使用下面的命令生成对应的 c++ 接口文件:

thrift --gen cpp echoapi.thrift

默认会生成一个“gen-cpp”的文件夹,里面包含下列文件:

echoapi_constants.cpp echoapi_constants.h echoapi_types.cpp echoapi_types.h EchoServer.cpp 

阅读全文…

sicp 笔记 (7)

第三章习题 3.21 – 3.37 的解答。

E-3.21: 因为 queue 只记录队头指针和队尾指针,而打印 front-ptr 的时候把整个队列都打印出来了,打印 rear-ptr 只打印最后一个元素。最后有一组“(# #)”应该是 map 的返回值。

(load "../examples/3.3.2-representing-queues.scm")

(define (print-queue q)
  (define (iter current end)
    (if (eq? current end)
      (map display (list (car current) "\n"))
      (begin (map display (list 

阅读全文…

C++11 中的 lambda 函数

c++ 标准库里有一个函数 sort(),可以对容器的元素进行排序。它的函数原型是(参考资料 [1]):

template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);

template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

其中第三个参数是一个比较函数,它接收两个容器中的两个元素,返回比较结果。如果没有第三个参数,默认按元素的升序排列。

例如,我们要将一个整型数组降序排列:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

static bool compare_int(int 

阅读全文…

git 使用笔记 (2)

合并指定文件

假设 master 中有文件 a 和 b,在分支 br1 中对 a 和 b 都进行了修改并且已经提交,如果只想把在 br1 中对 a 的修改合并到 master 中,执行命令:

git co master
git co br1 a

即先切换到要修改的分支(例如这里的 master),然后执行命令:

git co [分支名称] [要合并的文件1] [要合并的文件2] ...

分支的删除

假设有一个中心仓库 git-repos,有分支 master 和 br1;两个工作目录 …

阅读全文…