我永远找不到F#核心库的源代码。我知道它应该是 open 但谷歌对我帮助我找到它并不友好,如果是这样的话,我会查找Seq.fold的impl - 但这里有问题。
是否有人看到以下代码段存在任何问题:
let success = myList |>
Seq.fold
(fun acc item -> evaluation item)
false
逻辑上它似乎没有水,我可以并将试验测试它。但我想问社区。如果myList中的任何单个评估重新为false,我希望成功变量为false ...
所以测试:
let myList = [true; true]
let success = List.fold (fun acc item -> acc && item) true myList
和
let myList = [true; false; true]
let success = List.fold (fun acc item -> acc && item) true myList
确实返回了正确的结果 - 我会更加舒适地看到源......
答案 0 :(得分:4)
我认为你所寻找的是这样的:
let success = myList |>
Seq.fold
(fun acc item -> acc && evaluation item)
true
这也提供了“短圈”评估,因此,如果来自先前评估的acc为false
,则evaluation item
将无法运行且表达式将仅返回false
。
答案 1 :(得分:4)
Seq.exists将短路:
let success =
[1;2;3;40;5;2]
|> Seq.exists (fun item->(item>30))
|> not
答案 2 :(得分:1)
嗯,我最近升级了我的Visual Studio和F#,似乎无法找到包含F#库代码的目录。但是,就其价值而言,Seq.fold相当于以下内容:
let fold f seed items =
let mutable res = seed
for item in items do
res <- f res item
res
如果内部有任何单一评估 myList重新出错,我想要 成功变量是假的......
这取决于您的evaluation
功能的实施方式。如果您想在任何商品为假时返回false,请改用Seq.forall
。
答案 3 :(得分:0)
类似这样的事情
let l = [true; true; true; false; true]
let eval x = x
let x = (true, l) ||> Seq.fold(fun acc item -> acc && (eval item))
或者您想停止对第一个错误结果的评估?
let l = [true; false; true]
l |> Seq.forall id
答案 4 :(得分:0)
至于原始资料来源,以下是2010年8月10日发布的折叠函数。
真的不需要关心自己的实施,但看到它往往是有教育意义的。
// Seq module
let fold<'T,'State> f (x:'State) (source : seq<'T>) =
checkNonNull "source" source
use e = source.GetEnumerator()
let mutable state = x
while e.MoveNext() do
state <- f state e.Current;
state
// Array module
let fold<'T,'State> (f : 'State -> 'T -> 'State) (acc: 'State) (array:'T[]) = //'
checkNonNull "array" array
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
let mutable state = acc
let len = array.Length
for i = 0 to len - 1 do
state <- f.Invoke(state,array.[i])
state
// List module
let fold<'T,'State> f (s:'State) (list: 'T list) =
match list with
| [] -> s
| _ ->
let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
let rec loop s xs =
match xs with
| [] -> s
| h::t -> loop (f.Invoke(s,h)) t
loop s list
// MapTree module (Used by Map module)
let rec fold (f:OptimizedClosures.FSharpFunc<_,_,_,_>) x m =
match m with
| MapEmpty -> x
| MapOne(k,v) -> f.Invoke(x,k,v)
| MapNode(k,v,l,r,_) ->
let x = fold f x l
let x = f.Invoke(x,k,v)
fold f x r
// Map module
let fold<'Key,'T,'State when 'Key : comparison> f (z:'State) (m:Map<'Key,'T>) = //'
let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(f)
MapTree.fold f z m.Tree
// SetTree module (Used by Set module)
let rec fold f x m =
match m with
| SetNode(k,l,r,_) ->
let x = fold f x l in
let x = f x k
fold f x r
| SetOne(k) -> f x k
| SetEmpty -> x
// Set module
let fold<'T,'State when 'T : comparison> f (z:'State) (s : Set<'T>) = //'
SetTree.fold f z s.Tree
答案 5 :(得分:0)
我知道这是一个老问题,但以下内容可能与那些有类似问题的人有关。
关于此处的具体问题
只要Sequence中的一个元素为false,就会存在一个返回false的函数:Seq.forAll
。
事实上,这个问题的最简单答案是:
let success = Seq.forAll evaluation myList
更容易理解
let success = not (Seq.exists evaluation myList)
在TechNeilogy’s (rewritten) answer和此答案中,evaluation
函数未在评估折叠的第一个项目之后的项目上进行评估。
但是,正如Pascal Cuoq正确地指出的那样,在the accepted answer by Wesley Wiser中,列表其余部分的所有元素仍然被迭代,这是无用的。
相反,Seq.forAll
实际上在没有用处继续时停止迭代。 Seq.exists
,Seq.takeWhile
,...
关于一般折叠的短路
还有一些人想要折叠折叠。它可以做到。
步骤1:定义一个文件夹,其中指示状态在遍历源序列的其余部分期间不会发生变化,并且折叠应该短路。
第2步:使用Seq.scan
代替fold
。
Seq.scan
与fold
类似,采用相同的参数,但按需计算,不仅返回最终状态,还返回所有中间状态和最终状态的序列。
由此得出:Seq.last (Seq.scan folder initialState mySequence) = Seq.fold folder initialState mySequence
第3步:在Seq.scan
的输出上使用短路功能。接受您的选择:Seq.takeWhile
,Seq.forall
,Seq.exists
,...
在以下示例中,当找到重复元素时,状态变为None
,这意味着扫描可能会被短路。
let allDistinct mySequence =
let folder state element =
match state with
| Some elementsSoFar when not (Set.contains element elementsSoFar) ->
Some (Set.add element elementsSoFar)
| _ ->
None
let initialState = Some Set.empty
let scanning = Seq.scan folder initialState mySequence
Seq.forall Option.isSome scanning