F#中的递归lambda函数

9

请看以下示例代码(暂时忽略其效率低下的问题):

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##处使用它。

3个回答

19

是的,可以使用所谓的Y组合子(或不动点组合子)来实现。例如:

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入门可能也会有所帮助。

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

你的代码(这里省略类型注释)是一个标准结构,更加表达清晰。

let listToString lst =

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

    loop "" lst

0
请注意,尽管您说只使用该函数一次,但从技术上讲,您通过名称引用它两次,因此给它命名是有意义的。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接