0

简而言之:在 F# 中做“递归列表理解”的最惯用的方法是什么?

更详细:正如我目前所了解到的(我是 F# 新手),我们基本上有以下工具来“构建”列表:List.map 和列表理解。恕我直言,它们或多或少都做同样的事情,它们通过“更改”给定列表的元素来生成一个列表(在理解的情况下,给定列表的形式为 [k..n])。

我想要做的是归纳建立列表(在人们问之前:除了好奇之外别无其他原因),即是否有任何内置函数具有人们对名为“List.maplist”之类的函数所期望的行为可能需要作为论据

一个函数 f : 'a List -> 'a 和一个 n : int,

返回列表

[... ; f (f []) ; f [] ] 的长度为 n。

为了说明我的意思,我自己编写了这样一个函数(作为练习)

let rec recListComprehension f n =
    if n=0 then []
    else
        let oldList = recListComprehension f (n-1)
        f (oldList) :: oldList 

或者可读性差一点,但反过来又是尾递归的:

let rec tailListComprehension f n list = 
    if n=0 then list
    else tailListComprehension f (n-1) ((f list)::list)

let trecListComprehension f n = tailListComprehension f n []

例如,可以通过以下方式生成包含前 200 个斐波那契数的列表

let fiboGen =
    function
    | a::b::tail -> a+b
    | _ -> 1UL

trecListComprehension (fiboGen) 200

总结一下这个问题:F# 中是否有一个内置函数,其行为或多或少类似于“trecListComprehension”,如果没有,实现这种功能的最惯用方式是什么?

PS:抱歉有点冗长..

4

3 回答 3

3

在 F# 中执行“递归列表理解”的最惯用方法是什么?

这是风格的问题。你会更频繁地遇到高阶函数。对于某些情况,例如表达嵌套计算或实现惰性,使用序列表达式似乎更自然。

为了说明,您的示例是用序列表达式编写的:

let rec recListComprehension f n = seq { 
    if n > 0 then
        let oldList = recListComprehension f (n-1)
        yield f oldList
        yield! oldList }

recListComprehension fiboGen 200 |> Seq.toList

你有一个非常易读的函数,同时具有惰性和尾递归性,而使用Seq.unfold.

类似地,笛卡尔积的嵌套计算使用序列表达式/列表理解更具可读性:

let cartesian xs ys = 
    [ for x in xs do
        for y in ys do
          yield (x, y) ]

而不是使用高阶函数:

let cartesian xs ys = 
    List.collect (fun x -> List.map (fun y -> (x, y)) ys) xs

我曾经问过你可能感兴趣的列表理解和高阶函数之间的区别。

于 2013-05-07T20:41:51.217 回答
2

你基本上是fold在数字范围内。所以可以写成:

let listComp f n = List.fold (fun xs _ -> f xs :: xs) [] [1 .. n]

这具有优雅处理负值的额外好处n

于 2013-05-07T22:20:00.660 回答
0

你可以先做一个 Seq.unfold,然后再做 Seq.toList。

请参阅此处的示例:

let seq1 = Seq.unfold (fun state -> if (state > 20) then None else Some(state, state + 1)) 0

printfn "The sequence seq1 contains numbers from 0 to 20." 
for x in seq1 do printf "%d " x

let fib = Seq.unfold (fun state ->
    if (snd state > 1000) then None
    else Some(fst state + snd state, (snd state, fst state + snd state))) (1,1)

printfn "\nThe sequence fib contains Fibonacci numbers." 
for x in fib do printf "%d " x
于 2013-05-07T20:08:46.937 回答