2009-05-23 61 views
7

拿这个例子的代码(忽略它是暂时效率极其低下)递归lambda表达式

let listToString (lst:list<'a>) = ;;' prettify fix 

    let rec inner (lst:list<'a>) buffer = ;;' prettify fix 
     match List.length lst with 
     | 0 -> buffer 
     | _ -> inner (List.tl lst) (buffer + ((List.hd lst).ToString())) 

    inner lst "" 

这是我一直在F#跨越未来一个共同的模式,我需要有一个内部函数谁递归本身超过一些价值 - 我只需要这个函数一次,是否有任何可能从它内部调用一个lambda自我(一些魔术关键字或其他)?我想代码看起来像这样:

let listToString2 (lst:list<'a>) = ;;' prettify fix 

    (fun 
     (lst:list<'a>) buffer -> match List.length lst with ;;' prettify fix 
           | 0 -> buffer 
           | _ -> ##RECURSE## (List.tl lst) (buffer + ((List.hd lst).ToString())) 
    ) lst "" 

但正如你所期望的有没有办法指在自身内部匿名函数,在这里我把## RECURSE ##

回答

17
这是需要

是的,可以使用所谓的y-combinators(或fixed-point combinators)。例如:

let rec fix f x = f (fix f) x 

let fact f = function 
| 0 -> 1 
| x -> x * f (x-1) 


let _ = (fix fact) 5 (* evaluates to "120" *) 

我不知道F#的文章,但这个haskell entry也可能会有所帮助。

但是:如果有其他选择,我不会使用它们 - 它们很难理解。

你的代码(这里省略了类型注释)是一个标准的构造,更富有表现力。

let listToString lst = 

    let rec loop acc = function 
     | [] -> acc 
     | x::xs -> loop (acc^(string x)) xs 

    loop "" lst 
1

注意,虽然你说你使用的功能只有一次,在技术上你是指它的名字两次,这就是为什么它是有道理的,给它一个名字。