Seq.fold和布尔累加器

时间:2010-10-18 18:13:13

标签: f#

我永远找不到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

确实返回了正确的结果 - 我会更加舒适地看到源......

6 个答案:

答案 0 :(得分:4)

我认为你所寻找的是这样的:

let success = myList |>
                    Seq.fold
                        (fun acc item -> acc && evaluation item)
                        true

这也提供了“短圈”评估,因此,如果来自先前评估的acc为false,则evaluation item将无法运行且表达式将仅返回false

MSDN documentation for fold operator

答案 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

API documentation

更容易理解
let success = not (Seq.exists evaluation myList)

TechNeilogy’s (rewritten) answer和此答案中,evaluation函数未在评估折叠的第一个项目之后的项目上进行评估。 但是,正如Pascal Cuoq正确地指出的那样,在the accepted answer by Wesley Wiser中,列表其余部分的所有元素仍然被迭代,这是无用的。 相反,Seq.forAll实际上在没有用处继续时停止迭代。 Seq.existsSeq.takeWhile,...

也是如此

关于一般折叠的短路

还有一些人想要折叠折叠。它可以做到。

步骤1:定义一个文件夹,其中指示状态在遍历源序列的其余部分期间不会发生变化,并且折叠应该短路。

第2步:使用Seq.scan代替foldSeq.scanfold类似,采用相同的参数,但按需计算,不仅返回最终状态,还返回所有中间状态和最终状态的序列。 由此得出:Seq.last (Seq.scan folder initialState mySequence) = Seq.fold folder initialState mySequence

第3步:Seq.scan的输出上使用短路功能。接受您的选择:Seq.takeWhileSeq.forallSeq.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