近来想学习函数式编程。
但是一直不知道怎么展开这个学习过程,目前的研究进度也不深入,想讲解一些原理也无从下手。
先简单的上一些算法,逐步分析语法和思想。虽然程度不深,但至少能记录这个过程。
本例子用F#编写,是一种强类型,非纯函数式编程语言,在.net平台上运行,实际上为了兼容.net平台,你可以使用各种.net的基本类型和库。
C#的测试结果,从结果上看没有问题。
F#源码
1 namespace Heron.Helpers 2 3 open System.Text 4 open System.Security.Cryptography 5 6 module Encrypt = 7 let Sha1Hash (str : string) = 8 let sha1 = SHA1.Create () 9 let sha1arr = sha1.ComputeHash (Encoding.UTF8.GetBytes (str)) 10 let sha1str = String.concat "" (Array.init 20 (fun i -> sprintf "%02x" sha1arr.[i])) 11 sha1str 12 13 let Md5Hash (str : string) = 14 let md5 = MD5.Create () 15 let md5arr = md5.ComputeHash (Encoding.UTF8.GetBytes (str)) 16 let md5str = String.concat "" (Array.init 16 (fun i -> sprintf "%02x" md5arr.[i])) 17 md5str
短短数行就完成,是不是很简洁呢。
namespace Heron.Helpers open System.Text open System.Security.Cryptography /// 这段不用多说,namespace和C#中的功能一样,声明命名空间。 /// open相当于using ,导入一个命名空间
module Encrypt = /// 这里的module是用来区分个模块功能的,对程序意义不大,在C#里被当作一个静态类处理兼容。F#是缩进敏感的语言,缩进比这段语句多一层的都属于这个模块下面的。所以下面的两个函数可以理解为这个模块的静态方法。
let Sha1Hash (str : string) = let sha1 = SHA1.Create () let sha1arr = sha1.ComputeHash (Encoding.UTF8.GetBytes (str)) let sha1str = String.concat "" (Array.init 20 (fun i -> sprintf "%02x" sha1arr.[i])) sha1str /// let是用来绑定一个标识符,可以是实数,可以是字符串,可以是对象,也可以是函数,这里绑定的就是一个函数,带有一个string类型的参数str,最后一行为返回值,这里就是返回sha1str这个标识。实际上纯函数语言里是没有变量的,也没有基本类型,所有的东西都是函数,比如 let a = 0,你可以理解为没有参数,返回int的函数。F#为了兼容.net平台,类型都是静态绑定,靠自动推算来得到类型。 /// 这里用到的F#特性不多,只有第4行用到一点。可能看起来有点晕,我们来分解一下 Array.init 20 (fun i -> sprintf "%02x" sha1arr.[i]) /// Array.init 这是一个函数,有两个参数,第一个表示返回的数组个数,第二个参数为一个匿名函数,就是括号里的内容(fun i -> sprintf "%02x" sha1arr.[i])。这个函数会迭代i 从0到19 刚好对应sha1arr的下标,然后一次转为16进制的数表示,不足的前面补零。 String.concat "" Array /// 这个是把一个数组元素拼接为一个字符串的函数,第一个参数是拼接的符号,这里是空字符串,第二个参数是数组,就是上面生成的20个16进制的数。 /// 是不是代码简洁了很多呢
以后可能会陆续带来参数函数,返回值函数等高阶函数和泛型的随笔。不过我还是希望从实际数据着手,要有实际应用的空间。因为现在掌握的也不深,也没多少东西卖弄。
以后我会慢慢收集各种实用的算法,然后形成一个工具包,等实用度达到一定基础后会发布出来。不知道大家看好不。
如果大家有对函数编程的独特见解,也欢迎留言讨论。