简而言之:在F#中进行“递归列表理解”的最常用方法是什么?
更详细:正如我迄今所学到的(我是F#的新手),我们基本上有以下工具来“建立”列表:List.map和list comprehension。 Imho他们或多或少都做同样的事情,他们通过“改变”给定列表的元素生成一个列表(在理解的情况下,给定列表的形式为[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:对不起有点啰嗦..
答案 0 :(得分: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
我曾经问过您可能感兴趣的differences between list comprehension and high-order functions。
答案 1 :(得分:2)
你基本上是fold
数字范围。所以可以这样写:
let listComp f n = List.fold (fun xs _ -> f xs :: xs) [] [1 .. n]
这样可以优雅地处理n
的负值。
答案 2 :(得分:0)
你可以做一个Seq.unfold,然后做Seq.toList。
请参阅here中的示例:
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