Fre*_*old 7 f# functional-programming
我试图学习F#.我是一个完全的初学者,所以这对你们来说可能是一个小问题:)
我有以下功能:
let removeEven l =
let n = List.length l;
let list_ = [];
let seq_ = seq { for x in 1..n do if x % 2 <> 0 then yield List.nth l (x-1)}
for x in seq_ do
let list_ = list_ @ [x];
list_;
Run Code Online (Sandbox Code Playgroud)
它需要一个列表,并返回一个包含所有数字的新列表,它放在原始列表中的奇数索引处,所以 removeEven [x1;x2;x3] = [x1;x3]
但是,我得到了我最喜欢的错误消息: Incomplete construct at or before this point in expression...
如果我在行的末尾添加打印,而不是list_:
...
print_any list_;
Run Code Online (Sandbox Code Playgroud)
问题是固定的.但我不想打印清单,我想退货!
是什么导致这个?为什么我不能退回我的清单?
编辑:如果我正确理解你的要求,这里是你的函数完成功能而不是命令式的版本,它删除了具有奇数索引的元素.
let removeEven list =
list
|> Seq.mapi (fun i x -> (i, x))
|> Seq.filter (fun (i, x) -> i % 2 = 0)
|> Seq.map snd
|> List.ofSeq
> removeEven ['a'; 'b'; 'c'; 'd'];;
val it : char list = ['a'; 'c']
Run Code Online (Sandbox Code Playgroud)
要首先回答您的问题,编译器会抱怨,因为for循环内部存在问题.在F#中,let用于声明值(这些值是不可变的,以后不能在程序中更改).它不是C#中的声明 - let只能用作另一个表达式的一部分.例如:
let n = 10
n + n
Run Code Online (Sandbox Code Playgroud)
实际上意味着您希望n符号引用10表达式中的值n + n.你的代码的问题是你let没有任何表达式使用(可能是因为你想使用可变变量):
for x in seq_ do
let list_ = list_ @ [x] // This isn't assignment!
list_
Run Code Online (Sandbox Code Playgroud)
有问题的行是一个不完整的表达式 - let不允许使用这种方式,因为它不包含任何表达式(list_不会从任何代码访问该值).您可以使用mutable变量来更正代码:
let mutable list_ = [] // declared as 'mutable'
let seq_ = seq { for x in 1..n do if x % 2 <> 0 then yield List.nth l (x-1)}
for x in seq_ do
list_ <- list_ @ [x] // assignment using '<-'
Run Code Online (Sandbox Code Playgroud)
现在,这应该可行,但它不是真正的功能,因为你正在使用命令式变异.此外,使用附加元素@在函数式语言中是非常低效的.因此,如果您想使代码正常运行,您可能需要使用不同的方法.这两个答案都显示了一个很好的方法,虽然我更喜欢Joel的例子,因为索引到一个列表(在Chaos的解决方案中)也不是很有用(没有指针算法,所以它也会慢一些) .
可能最经典的功能解决方案是使用该List.fold函数,该函数将列表的所有元素聚合成一个结果,从左到右:
[1;2;3;4;5]
|> List.fold (fun (flag, res) el ->
if flag then (not flag, el::res) else (not flag, res)) (true, [])
|> snd |> List.rev
Run Code Online (Sandbox Code Playgroud)
这里,聚合期间使用的状态是布尔标志,指定是否包括下一个元素(在每个步骤中,我们通过返回来翻转标志not flag).第二个元素是到目前为止聚合的列表(我们el::res仅在flag设置时添加元素.fold返回后,我们使用snd获取元组的第二个元素(聚合列表)并使用它来反转它List.rev,因为它是在反向中收集的order(这比追加到最后使用更有效res@[el]).