维坦

感谢您的关注!


  • Jul
    30

    难得的 F# 好文

    Filed under: 编程; Tagged as: ,

    我本人是通过 F# 了解了 .NET
    进而了解了一些 C#
    因此我对于 F# 的好多见解是片面的

    例如: 我曾经在学习 F# 之后好久都不能理解 type

    今天见到一篇好文, 文章的作者是从 C#3.0 的角度看待 F#, 深入浅出, 角度客观, 可以说是难得的好文~!~

    从 C#3.0 到 F#
    作者:Allen Lee

    1 Comment
  • Jul
    24

    Kean与F# 中文翻译同步更新

    Filed under: 作品; Tagged as: , ,

    最后更新: 2008年7月24日 (21篇)
    原文作者: Kean Walmsley
    文档格式: Word文档 (*.doc) | 7zip (*.7z)

    完整下载: http://www.box.net/shared/qsmfdafvcn


    文章目录:

    • 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#程序

    部分下载: http://www.box.net/shared/x8d3ydgqb2


    关于 F# 语言:

    • F# 是一门函数式编程语言! (Functional Programming Language)
    • 官方网站: http://msdn.microsoft.com/zh-cn/fsharp/
    • 目前已经进入产品化阶段, 预计今夏(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个.

    6 Comments
  • Jul
    23

    F#生成MD5字典

    Filed under: 编程; Tagged as: , ,

    之前的一篇文章提到过一种逆向思维求解MD5的方法.

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

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

     
    #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+

    1 Comment
  • Jul
    21

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

    Filed under: 随笔; Tagged as:

    背景:
    嘎纳广告节(Cannes Lions Advertising Campaign)源于嘎纳电影节, 1954年, 由电影广告媒体代理商发起组织了嘎纳国际电影广告节, 希望电影广告能同电影一样受到世人的认同和瞩目.
    吉百利(Cadbury Schweppes): 全球第一大糖果公司, 第二大口香糖公司, 第三大软饮料公司.

    歌曲: In the air tonight

    歌手: Collins phil

    专辑: Face Value

    下载: MP4 BT

    1 Comment
  • Jul
    18

    通过 WCF 认识 F# 中的类型

    Filed under: 编程; Tagged as:

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

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

     
     
    (* 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 }
     

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

     
    // 给 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
     
     
    // 以下是客户端服务引用自动生成的代码片段
        [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 之类的呢? 试一下便清楚了!

     
    // 修改契约 返回 list, 也就是 F# 特有的数据类型 Boy list.
    // seq 会返回同样的效果, 不再重复了.
    [<ServiceContract(Name = "Wcf")>]
    type Wcf() =
        let boy =
          { Name = "colder"
            Age = Int32.MaxValue }
        [<OperationContract>]
        member t.BoyList() =
            [boy]
     
     
    // 生成的 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 这样内功深厚的武林高手, 否则我会一直追问直到找出原因. 事实上我只是个样样好奇却样样平庸的功夫小子, 玩弄些花拳绣腿罢了, 所以尝试只能在此结束, 无法继续找出真正的答案了.

    No Comments
  • Jul
    15

    F# Compiler 1.9.4.19 (msi)

    Filed under: 编程; Tagged as:

    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 的原文

    No Comments
  • Jul
    8

    System.Data.SQLite DataType

    Filed under: 编程; Tagged as:

    虽然上篇文章中提到 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"
    No Comments