码迷,mamicode.com
首页 > 其他好文 > 详细

利用F#编写、理解Y组合子函数

时间:2015-05-03 20:16:40      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:

 赵劼的博客《使用Lambda表达式编写递归函数》中用C#实现了为函数求出 Y 组合子的函数。C#代码生涩,难以阅读,原代码如下:

        static Func<T, TResult> Fix<T,TResult>(Func<Func<T, TResult>, Func<T, TResult>> f)

        {

            return x => f(Fix(f))(x);

        }

 

        static Func<T1, T2, TResult> Fix<T1,T2, TResult>(Func<Func<T1, T2, TResult>, Func<T1, T2, TResult>> f)

        {

            return (x, y) => f(Fix(f))(x, y);

        }

 


代码调用如下

var fac = Fix<int, int>(f => x => x <= 1 ? 1 :x * f(x - 1)); 

 


让代码变得容易阅读原是F#的强项,我们尝试用F#重写上面的代码,把 Fix 函数改名为 Y,得出以下代码:

 

let rec Y f x = f (Y f) x

 

 



 
代码调用则如下

    let fac =

        Y (fun yf x ->

                if x <= 1 then 1

                else x * yf(x - 1))

 


现在,Y 组合子函数一下子就明撩了:它就是定义了一个高阶函数 Y f ,实现为 f (Y f)

我们把 Y f 代入下面的 fac 函数,这里,参数 f 其实被赋值为 fun yf x -> ...

 关键: yf 赋值为Y f,也就是 Y (fun yf  x),因此产生了递归。

另外,需要注意的是: let rec Y f x = f (Y f) x 不能改写为 let rec Y f = f (Y f)

理论上,两者的 Y 等义,但是,后者会在 被调用时,先计算出 Y f 的值,最后因为无法结束递归而导致堆栈溢出。

 

而前者不计算 Y f,直接计算 Y f x,在 x <= 1 时候停止递归


================================================================================

什么?Y 组合子有什么用?就是在你需要使用匿名函数,但是同时需要递归的时候,有了 Y 组合子你才可以同时拥有两者。

譬如,可以这样: 

        a
        |> (+) 4
        |> Y (fun yf x ->

                    if x <= 1 then 1

                    else x * yf(x - 1))    

 

 

 

 

 

 

 

 

 

 

 

利用F#编写、理解Y组合子函数

标签:

原文地址:http://www.cnblogs.com/greatim/p/4474454.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!