随笔-341  评论-2670  文章-0  trackbacks-0
 
     摘要: 有的时候,IO的异常处理由于需要一个IOEnv类型的参数而显得非常麻烦。这个时候我们可以定制自己的一套异常处理系统,从而让程序变得清晰起来。自己的异常处理系统不同于IO,是没有副作用的函数集合。下面让我们看一看如何使用自定义的异常处理系统来分析一个四则运算表达式。  阅读全文
posted @ 2008-12-18 21:23 陈梓瀚(vczh) 阅读(1442) | 评论 (0)编辑 收藏
     摘要: 说到底Kernel FP是一个脚本引擎,所以是需要API的。接下来的代码用来加载一些Kernel FP代码文件,并执行main函数。  阅读全文
posted @ 2008-12-17 19:15 陈梓瀚(vczh) 阅读(1627) | 评论 (1)编辑 收藏
     摘要: 我们知道,循环本身是没有返回值的。所以在纯函数式语言下,跟IO有关的循环才有足够的副作用来产生价值。于是利用IO Monad,我们就可以实现循环了。循环是一个函数:  阅读全文
posted @ 2008-12-15 07:56 陈梓瀚(vczh) 阅读(2141) | 评论 (2)编辑 收藏
     摘要: 前面说过,需要一个语法糖来组织IO,并且在其中的一步产生错误的时候立刻返回错误。现在我们看一段代码:  阅读全文
posted @ 2008-12-15 06:22 陈梓瀚(vczh) 阅读(1469) | 评论 (0)编辑 收藏
    由于Kernel FP是纯的,所以一个函数的输出只跟输入有关系,所以从屏幕上输入文字的函数read是不能定义成func read::string的。因为根据这个性质,read的结果必须是一样的。所以一定要在每一次read的时候给不同的参数。但是其实没关系,这个可以用编译器来解决,就算read的顺序是运行时决定的。同样的问题也出现在Haskell的IO Monad上,由于资料无穷多,我就不详细解释了。下面给出没有语法糖的,能够正常并确定顺序地使用IO函数的一段代码:

 1 data IOError
 2   = ioemessage string
 3 type IOEnv
 4 type IO T = IOEnv -> maybe (pair T IOEnv) IOError
 5 
 6 func read :: IO string alias "demo::read"
 7 func readint :: IO int alias "demo::readint"
 8 func write :: string -> IO void alias "demo::write"
 9 func writeln :: string -> IO void alias "demo::writeln"
10 func iovoid :: IO void alias "demo::iovoid"
11 
12 def (>>>) a b = a >>= \p->b
13 func return T :: T -> IO T
14 def return x e = success (pair x e)
15 func (>>=) T1 T2 :: IO T1 -> (T1 -> IO T2) -> IO T2
16 def (>>=) a b e = select a e of
17   case fail message : fail message
18   case success p : select p of
19     case pair x e2 : b x e2
20   end
21 end
22 
23 def ioseq ios = foldr iovoid (>>>) ios
24 
25 def mainIO_0 = 
26   read >>= \name->
27   read >>= \place->
28   writeln ("Hello "+name+" from "+place+".">>>
29   readint >>= \a->
30   readint >>= \b->
31   writeln (itoa (a+b)) >>>
32   writeln "Press [ENTER] to enter" >>>
33   read
34 
35 def mainIO_1 = ioseq (transform writeln ["genius","vczh"])

    mainIO_0使用类型系统强制了IO函数的执行顺序,mainIO_1证明了IO也是可以使用正常的操作函数去进行复杂操作的。不过mainIO_0那种写法还是挺不舒服的,这就是语法糖发挥作用的啦。我只需要给出一种相对好看的语法,然后在语法分析的时候翻译成这样就行了。

    这种写法的好处是,万一其中有一个IO出了问题,错误信息会直接传达出去,中断函数执行。而且整个函数都是在类型系统的保护之下的。
posted @ 2008-12-14 22:44 陈梓瀚(vczh) 阅读(1761) | 评论 (0)编辑 收藏
    考虑以下代码:
1 def overloading x = "General overloading"
2 func overloading::string->string
3 def overloading str = "String overloading"
4 func overloading T::list T->string
5 def overloading xs = "List overloading"

    这是三个函数,类型分别为:
1     func overloading T1 :: (<T1> -> (system.list system.char)) codefrom 125
2     func overloading :: ((system.list system.char-> (system.list system.char)) codefrom 127
3     func overloading T1 :: ((system.list <T1>-> (system.list system.char)) codefrom 129

    所以当我们写overloading的时候,究竟选择什么呢?三个类型都是可以接受的,而且都是可以完美通过类型推导的。于是我新加了一个规则。首先求出需要的具体类型(可能是含有参数的类型),然后计算从函数类型到具体类型所需要替换的类型参数的个数以及每个类型参数的解,最后计算出一个系数=数量×65536+解的深度和。

    深度的规定比较简单,基本类型深度为1,闭包类型为参数和结果两种类型的深度的最大值加1,带有参数的类型等于最大参数深度加1。所以在这个例子上,我们可以得到,T1到list char的解为T1=list char,list char到list char的解为0,list T1到list char的解为T1=char,系数分别是65538、0和65537,所以理所当然地挑选了第二个。下面看例子:
1 def main114 = overloading 1024
2 def main115 = overloading "Genius Vczh!"
3 def main116 = overloading [1,2,3]

    下面是运行结果:
1 main114返回值:"General overloading"
2 main115返回值:"String overloading"
3 main116返回值:"List overloading"
posted @ 2008-12-14 19:42 陈梓瀚(vczh) 阅读(1460) | 评论 (0)编辑 收藏
    现在的Kernel FP已经支持列表语法和操作符语法了。

    列表语法为[1,2,3,4,5]。原来是需要写成list 1 (list 2 (list 3 (list 4 (list 5 empty))))的。不过后面这种写法仍然是支持的。
    操作符可以自定义,凡是仅由“+-*/%<>=!&^|~@#$?”构成,而又不是“|”和“=”的记号都可以视为二元操作符。如果是+、-、*、/、%、<、<=、>、>=、==、!=、^、&&和||的话,优先级跟C++一样。如果是其他操作符,那么优先级一致而且最低。

    因为操作符也是个函数,因此将操作符作为函数使用的时候只需要加一对括号就可以了,不过中间不可以有空格。所以我们就可以定义“+”并写出下面的代码:
1 def (+= iadd
2 def (+= fadd
3 def (+= concat
4 def main102 = (+1 2
5 def main103 = (+1.0 2.0
6 def main104 = (+"Genius" " Vczh!"
7 def main105 = 1 + 2
8 def main106 = 1.0 + 2.0
9 def main107 = "Genius" + " Vczh!"

    下面是执行结果:
1 main102返回值:3
2 main103返回值:3.0
3 main104返回值:"Genius Vczh!"
4 main105返回值:3
5 main106返回值:3.0
6 main107返回值:"Genius Vczh!"

    操作符的优先级比函数低,因此sin a + sin b实际上是(sin a)+(sin b)。 于是下面的代码返回8.0:
1 def main108 = ln (exp 3.0+ ln (exp 5.0)

    有了操作符之后,就可以慢慢为IO、Exception等复杂对象建模并且开发语法糖了。
posted @ 2008-12-14 08:37 陈梓瀚(vczh) 阅读(1766) | 评论 (2)编辑 收藏
     摘要: 为了测试Kernel FP的健壮性以及进行一些bug的排除,一个四则运算式子的分析程序理所当然地就被实现了。代码如下:  阅读全文
posted @ 2008-12-13 07:13 陈梓瀚(vczh) 阅读(3341) | 评论 (2)编辑 收藏
     摘要: 经过1个小时的奋斗,修了3个bug,终于使得Kernel FP能运行的代码渐渐多了起来。现在可以看看纯函数式语言简洁的代码及运行结果啦!

下面是很多用于测试的main函数:  阅读全文
posted @ 2008-12-12 10:03 陈梓瀚(vczh) 阅读(1442) | 评论 (1)编辑 收藏
     摘要: Kernel FP已经可以运行小程序了。现在还处于测试阶段,过于复杂的程序估计是跑不过的。先简单介绍一下如何在C++调用Kernel FP的代码。  阅读全文
posted @ 2008-12-10 23:03 陈梓瀚(vczh) 阅读(1709) | 评论 (2)编辑 收藏
仅列出标题
共35页: First 21 22 23 24 25 26 27 28 29 Last