兰迪·波许教授的最后一课

兰迪·弗雷德里克·波许 (Randy Frederick Pausch)
美国卡内基梅隆大学的计算机科学人机交互及设计教授. 2006年9月, 他被诊断患有胰腺癌.
尽管进行了手术和化疗, 他还是于2007年 8月被告知癌细胞已经转移至肝臟及脾脏, 至多可以再存活3到6个月.

他的名字我是第一次听过, 不过作为模拟人生(SIMS)的设计者, 对于80后应该不会感到陌生了吧. 是他开创了虚拟实境这门学科.

不过我要说的不仅仅是这些, 视频中并没有过多的讲述计算机技术, 而是谈论实现儿时的梦想有多么的重要, 并且在时日不多的情况下仍然能够在1小时的演讲当中保持诙谐幽默.

让人羡慕的教育方式, 让人羡慕的学术氛围, 让人羡慕的人生经历.

VeryCD 上可以获得 AVI 和 WMV 两种格式的视频, 还有现场使用的 PPT

Kean 和 F#

最后更新: 2008年7月24日 (21篇)

原文作者: Kean Walmsley

文档格式: Word文档 (.doc) | 7zip (.7z)

完整下载

章节下载

文章目录:

  • A simple 3D LOGO implementation inside AutoCAD using F#
    在 AutoCAD 中使用 F# 实现 3D LOGO 的简单应用
  • Sectioning an AutoCAD solid using F#
    使用 F# 分割 AutoCAD 实体
  • Generating fractals inside AutoCAD using F#
    在 AutoCAD 中使用 F# 生成分形
  • Initialization code in your F# AutoCAD application
    AutoCAD程序初始化F#代码
  • Using AutoCAD 2009 s new transient graphics API to show point clouds from F#
    利用F#和AutoCAD 2009的新API临时图形来显示点云
  • New APIs in AutoCAD 2009
    AutoCAD 2009中新的API
  • Recursive F# code to generate random point clouds inside AutoCAD
    递归F#代码在AutoCAD中产生随机点云
  • Using Reflector to diagnose tail call optimization in F#
    使用Reflector对F#进行诊断跟踪优化
  • Pointing at clouds  more random musings on AutoCAD and F#
    点云 关于AutoCAD和F#的更多遐想
  • Parallelizing robotic AutoCAD hatching with F# and .Net
    使用F#及.NET实现并行智能AutoCAD填充
  • Robotic hatching inside AutoCAD using F# and .Net
    使用F#及.NET在AutoCAD中实现智能填充
  • Mardi Gras Super Tuesday and F#
    狂欢节 超级周二与F#
  • Using F# to simulate hardware behaviour
    使用F#模拟硬件行为
  • Using F# Asynchronous Workflows to simplify concurrent programming in AutoCAD
    在AutoCAD中使用F#异步工作流程简化并行程序
  • Turning AutoCAD into an RSS reader with F#
    在AutoCAD中使用F#实现RSS阅读器
  • Metaprogramming with AutoCAD - Part 3
    元编程与AutoCAD 第三部分
  • Metaprogramming with AutoCAD - Part 2
    元编程与AutoCAD 第二部分
  • Metaprogramming with AutoCAD - Part 1
    元编程与AutoCAD 第一部分
  • Getting the total volume of 3D solids in an AutoCAD model using F#
    使用F#获取AutoCAD模型中3D实体的总体积
  • More fun with F# and AutoCAD string extraction and manipulation
    F#更多有趣的东西与AutoCAD字符串的提取及操作
  • A mathematical F# application integrating with AutoCAD via .NET
    一个AutoCAD F# .NET的完整数学程序
  • F# - a perfect fit for AutoCAD .NET programming
    F# - 非常适合AutoCAD .NET程序开发么
  • My first F# application for AutoCAD
    我的第一份用于AutoCAD的F#程序

关于 F# 语言:

F# 是一门函数式编程语言! (Functional Programming Language)

官方网站

目前已经进入产品化阶段, 预计今夏(2008年)发布第一个CTP版

维护者: Don Syme

发布方式: Visual Studio 扩展

什么是函数式编程?

简单的定义是: 在函数式语言中, 函数是第一等公民.

函数式语言其实比你想象中的要多得多, 只不过它们长期处在计算机技术发展的边缘, 所以好多都是不为人知.

如: LISP, Scheme,Perl, ML, Miranda, Haskell, XSLT, Ruby, erlang, Ocaml 等等.

F# 有什么用?

形象的比喻: 用C#吸引C/C++程序员, 用VB.NET替换VB6, 用J#拉拢JAVA程序员, 那么F#就是招安那些处在边缘的函数式小语种, 这也就是为什么Kean会说 - F#是最适合AutoCAD开发的编程语言 - 的原因! Kean Walmsley是Autodesk的专家, 他从2007年10月31日起连续发表关于使用 F# 开发 AutoCAD 的文章, 但是由于我们平常所见到的编程技术多半是类 C 技术, 再加上 F# 时间较短, 所以Kean所研究的技术显然是有些超前了, 但是他对这门语言的崇拜显然已经达到了宗教般的高度, 这使我坚信他所追求的一定很有价值!

由于一些原因, Kean的博客不容易访问, 因此我会不间断的摘录并坚持翻译, 但仅限于F#有关的文章.

有趣的是: 在 Google 中搜索 F# 会返回近百万个匹配的结果, 而在百度中搜索就只会返回0个.

F#生成MD5字典

之前想到的一种逆向思维求解MD5的方法.

后来发现真的有人这么做了, 其中数据量最大的网站标称自己拥有4T的数据量, 可以解8位以下的数字和字母组合.

即然是之前自己有过的想法, 那就拿F#来具体实现一下吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#light
namespace ViTarn
module MD5
open System
open System.Data
open System.Diagnostics
open System.IO
open System.Security.Cryptography
open System.Text
// sqlite.phxsoftware.com
#r "System.Data.SQLite.DLL"
open System.Data.SQLite
// 数据库名
let dbFile = "db.sqlite"
// 连接字符串
let connString =
let csb = SQLiteConnectionStringBuilder ()
csb.DataSource <- dbFile
csb.ConnectionString
// 秒表
let watch = new Stopwatch ()
watch.Start()
// 为调试方便 输出对象并换行
let debug x =
x |> print_any
Console.WriteLine ()
// 从\' \'到\'~\'共95个常用于密码的字符 可以当成95进制看待
let n2cl n =
let rec prase n l =
let d = n % 95
let c = d + 32 |> char
let d = n - d
if d > 95 then
prase (d / 95) (c :: l)
else
c :: l |> List.to_array prase n []
// MD5加密字符串
let md5 (str : string) =
use md5Hasher = MD5.Create ()
str
|> Encoding.Default.GetBytes
|> md5Hasher.ComputeHash
|> Seq.map (fun x ->
x.ToString "x2")
|> Seq.fold (fun x y -> x + y) ""
// 创建数据库
if dbFile |> File.Exists |> not then
dbFile |> SQLiteConnection.CreateFile
use conn = new SQLiteConnection (connString)
let sql = "PRAGMA auto_vacuum = 1; " +
"PRAGMA encoding = \'UTF-8\'; " +
"PRAGMA page_size = 4096; " +
"PRAGMA synchronous = OFF; " +
"CREATE TABLE md5 (p VARCHAR(42) NOT NULL COLLATE NOCASE, s VARCHAR(9) NOT NULL COLLATE NOCASE);"
use cmd = new SQLiteCommand (sql, conn)
conn.Open ()
cmd.ExecuteNonQuery () |> ignore
conn.Close ()
let main _ =
let sql = "INSERT INTO md5 " +
"VALUES(?, ?); "
use conn = new SQLiteConnection (connString)
use cmd = new SQLiteCommand(sql, conn)
cmd.Parameters.AddRange [|new SQLiteParameter(); new SQLiteParameter()|]
conn.Open ()
use tr = conn.BeginTransaction ()
cmd.Transaction <- tr
for i = 0 to 857374 do
let s = new String (n2cl i)
let p = md5 s
cmd.Parameters.[0].Value <- p
cmd.Parameters.[1].Value <- s
cmd.ExecuteNonQuery () |> ignore
if i % 10000 = 0 then
i |> debug
tr.Commit()
conn.Close ()
main ()
watch.Elapsed |> debug
Console.ReadKey()

为什么是857374? 95 95 95 - 1 = 857374

模拟的95进制, 是从空格(\’ \’)到波浪线(\’~\’)的, 用ASCII表示就是32到126. 所在0 to 857374代表\’ \’到\’~~~\’

在我的电脑上耗时00:01:08

  • CPU: AMD3000+
  • RAM: 1G

以DEBUG模式运行 最终产生的数据库约36M+

吉百利大猩猩 - 2008嘎纳广告节

背景:

嘎纳广告节(Cannes Lions Advertising Campaign)源于嘎纳电影节, 1954年, 由电影广告媒体代理商发起组织了嘎纳国际电影广告节, 希望电影广告能同电影一样受到世人的认同和瞩目.

吉百利(Cadbury Schweppes), 全球第一大糖果公司, 第二大口香糖公司, 第三大软饮料公司.

  • 歌曲: In the air tonight
  • 歌手: Collins phil
  • 专辑: Face Value
  • 下载: MP4 BT

通过 WCF 认识 F# 中的类型

近来正在试着用 F# 实现自承载 WCF 服务, 供 Silverlight 调用.一些数据会通过 “添加服务引用” 这一功能, 实现从 F# 到 C# 的转换. 正好借此机会看下会发生什么样有趣的事情.

由于我要在服务端读取数据库, 之前的 LINQ to SQL 经历告诉我, 我应该为数据库的每个表定义相应的类, 以 Boy 表为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
(* F# 在类(Class)的定义方面是很灵活的从某种意义上讲 对类的表达近乎恶搞
因为类(Class)对 F# 来说只不过是个表达式而已 *)


// 可以这样:
type Boy1 =
val mutable _name :string
val mutable _age :int
member t.Name
with get() = t._name
and set(v) = t._name <- v
member t.Age
with get() = t._age
and set(v) = t._age <- v
new () =
{
_name = ""
_age = 0
}
// 这种形式要求必须实例化之后才能使用
let boya =
let boy = new Boy1()
boy._name <- "colder"
boy._age <- Int32.MaxValue
boy
// 或
let boyb = new Boy1(Name = "colder", Age = Int32.MaxValue)

// 还可以定义成这样:
type Boy2(name :string, age :int) =
let mutable _name = name
let mutable _age = age
member t.Name
with get() = _name
and set(v) = _name <- v
member t.Age
with get() = _age
and set(v) = _age <- v
// 实例化时参数即为字段
let boyc = new Boy2("colder", Int32.MaxValue)

// 这两种方式定义的类 都是在模仿 C# 定义类的方式
// 不过怎么看都没有 C#3.0 使用的 { get; set; } 形式简单
// 可不可以使用 Records 呢?
// 答案是肯定的 生成的客户端代码并没有区别
type Boy =
{
mutable Name :string
mutable Age :int
}
// 实例化也是最简单的
let boyd =
{
Name = "colder"
Age = Int32.MaxValue
}

验证的依据很简单, 在服务端开放数据契约和服务契约, 之后生成客户端代码, 看是否有异常就可以了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 给 Boy 记录加上相关的属性
[<DataContract(Name="Boy")>]
type Boy =
{
[<DataMember(Order = 1)>]
mutable Name :string
[<DataMember(Order = 2)>]
mutable Age :int
}
// 返回值采用标准的 List<T> 泛型
// 也就是微软官方视频教程中提到的 LINQ 表达式的 ToList() 方法返回的类型
[<ServiceContract(Name = "Wcf")>]
type Wcf() =
let boy =
{
Name = "colder"
Age = Int32.MaxValue
}
[<OperationContract>]
member t.BoyListT() =
let list = new System.Collections.Generic.List<Boy>()
list.Add boy
list

使用 WCF 工具生成客户端代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// 以下是客户端服务引用自动生成的代码片段
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Runtime.Serialization.DataContractAttribute(Name="Boy", Namespace="http://schemas.datacontract.org/2004/07/")]
public partial class Boy : object, System.ComponentModel.INotifyPropertyChanged
{
private string NameField;
private int AgeField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name
{
get
{
return this.NameField;
}
set
{
if ((object.ReferenceEquals(this.NameField, value) != true))
{
this.NameField = value;
this.RaisePropertyChanged("Name");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(Order=1)]
public int Age
{
get
{
return this.AgeField;
}
set
{
if ((this.AgeField.Equals(value) != true))
{
this.AgeField = value;
this.RaisePropertyChanged("Age");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}

上面这个例子生动的说明: 什么时候该使用 Class, 什么时候该使用 Records.个人理解, 有行为的才是 Class, 只是数据的就应该是 Records.

难怪蔡学镛先生会提醒初学 F# 的人 宁可矫枉过正 也要保持 FP 的原汁原味 只有这样才能深刻体会 FP 的真谛

数据契约弄清楚了, 那 WCF 操作契约的返回值可不可以采用 F# 常见的 list 或 seq 之类的呢? 试一下便清楚了!

1
2
3
4
5
6
7
8
9
10
11
12
// 修改契约 返回 list, 也就是 F# 特有的数据类型 Boy list.
// seq 会返回同样的效果, 不再重复了.
[<ServiceContract(Name = "Wcf")>]
type Wcf() =
let boy =
{
Name = "colder"
Age = Int32.MaxValue
}
[<OperationContract>]
member t.BoyList() =
[boy]

这次客户端代码有点奇怪了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 生成的 C# 代码是个畸型的怪胎...
// 不可思议的类名: ListOfBoyMTRdQN6P
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.Runtime.Serialization.DataContractAttribute(Name="ListOfBoyMTRdQN6P", Namespace="http://schemas.datacontract.org/2004/07/Microsoft.FSharp.Collections")]
public partial class ListOfBoyMTRdQN6P : object, System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}

看到了吧, 此 list 非彼 List, 真的想不通把 Boy 放到 list 以后究竟发生了什么, 导致离开 F# 环境, 取出的 Boy 就不再是 Boy 了 (ListOfBoyXXXXXXXX)

我并不是一个像 Q.yuhen 这样内功深厚的武林高手, 否则我会一直追问直到找出原因. 事实上我只是个样样好奇却样样平庸的功夫小子, 玩弄些花拳绣腿罢了, 所以尝试只能在此结束, 无法继续找出真正的答案了.

F# Compiler 1.9.4.19 (Msi)

F# 1.9.4.19 版发布了, 这是个微量更新版本, 主要涉及以下三个方面:

  • 修正与 Mono 的兼容性问题.
  • WebRequest.GetResponseAsync 方法从 FSharp.Core.dll 中移除了.
    之前因为这个问题导致 F# 无法摆脱对 .NET 完整版的依赖, 也因此无法编译 Silverlight 这类 Core-CLR 代码.
    但问题是, 即使如此我们又如何使用 F# 来实现 Silverlight2 呢? 说真的, SL2 的编译和打包方式真的很诡异, 之前曾经有研究过, 那些 xaml 文件会被嵌入”项目名.g.xaml”, 而且是前所未有的MemoryStream类型, 几次下来还是一头雾水. 期待 Demo 的出现.
  • 修正与 .NET 3.5 SP1 Beta 的兼容性问题

详见 Don 的原文

System.Data.SQLite DataType

虽然上篇文章中提到 SQLite 是弱类型数据库, 但对于 System.Data.SQLite 来说, 为了更好的与 Ado.NET 2.0 互操作, 作者仍然建议在创建表的时候就指定类型, 以方便程序进行类型转换, 下面是类型关键字列表:

  • DbType.Boolean BIT YESNO LOGICAL BOOL
  • DbType.Byte TINYINT
  • DbType.Int16 SMALLINT
  • DbType.Int32 INT
  • DbType.Int64 INTEGER BIGINT COUNTER AUTOINCREMENT IDENTITY LONG
  • DbType.Single REAL
  • DbType.Double DOUBLE FLOAT
  • DbType.Decimal NUMERIC DECIMAL MONEY CURRENCY
  • DbType.String CHAR NCHAR VARCHAR NVARCHAR TEXT NTEXT LONGTEXT LONGCHAR LONGVARCHAR STRING MEMO NOTE
  • DbType.Binary BLOB BINARY VARBINARY IMAGE GENERAL OLEOBJECT
  • DbType.Guid GUID UNIQUEIDENTIFIER
  • DbType.DateTime TIME DATE DATETIME SMALLDATE SMALLDATETIME TIMESTAMP

有两点需要注意:

  • SQLite 主键默认的 INTEGER 类型对应的是 Int64, 而 INT 对应的是 Int32.
  • 日期和时间类型最终存储为字符串, 所以格式必须符合ISO8601标准:
    yyyy-MM-dd HH:mm:ss
    yyyyMMddHHmmss
    yyyyMMddTHHmmssfffffff
    yyyy-MM-dd
    yy-MM-dd
    yyyyMMdd
    HH:mm:ss
    THHmmss