Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#谓词求值为true时停止Seq.map_Map_F#_Seq - Fatal编程技术网

F#谓词求值为true时停止Seq.map

F#谓词求值为true时停止Seq.map,map,f#,seq,Map,F#,Seq,我目前正在以类似的方式生成一个序列: migrators |> Seq.map (fun m -> m()) migrator函数最终返回一个有区别的联合,如: type MigratorResult = | Success of string * TimeSpan | Error of string * Exception 我想在遇到第一个错误时停止映射,但我需要在最后一个序列中包含错误 我有如下内容向用户显示最后一条消息 match results |> List.re

我目前正在以类似的方式生成一个序列:

migrators
|> Seq.map (fun m -> m())
migrator
函数最终返回一个有区别的联合,如:

type MigratorResult =
| Success of string * TimeSpan
| Error of string * Exception
我想在遇到第一个
错误时停止
映射
,但我需要在最后一个序列中包含
错误

我有如下内容向用户显示最后一条消息

match results |> List.rev with
| [] -> "No results equals no migrators"
| head :: _ ->
   match head with
   | Success (dt, t) -> "All migrators succeeded"
   | Error (dt, ex) -> "Migration halted owing to error"
因此,我需要:

  • 当其中一个映射步骤产生
    错误时停止映射的方法
  • 将该错误添加到序列的最后一个元素是一种方法

  • 我很感激除了
    map
    之外,还有一种不同的排序方法可以做到这一点,我对F#是新手,在线搜索还没有产生任何结果

    我想这里有多种方法,但一种方法是使用展开:

    migrators 
    |> Seq.unfold (fun ms ->
        match ms with
        | m :: tl -> 
            match m () with
            | Success res -> Some (Success res, tl)
            | Error res   -> Some (Error res, [])
        | [] -> None)
    |> List.ofSeq
    

    注意末尾的seq
    列表,它只是用来实现序列的。另一种方法是使用序列理解,有些人可能会说这会产生更清晰的代码。

    我认为@scrwtp的答案可能是最好的方法,如果您的输入相当小(您可以将其转换为F#list以使用模式匹配)。我将再添加一个版本,当您的输入只是一个序列并且您不想将其转换为列表时,该版本就可以工作

    本质上,您希望做一些类似于
    Seq.takeWhile
    的事情,但它在末尾为您提供了一个附加项(谓词失败的那一项)

    为了使用一个更简单的示例,下面返回序列中的所有数字,直到一个数字可被5整除:

    let nums = [ 2 .. 10 ]
    
    nums
    |> Seq.map (fun m -> m % 5)
    |> Seq.takeWhile (fun n -> n <> 0)
    
    这里唯一难看的是,然后需要使用
    mapi
    concat
    再次展平序列


    这不是很好,所以最好定义自己的高阶函数,比如
    Seq.takentilafter
    ,它封装了您需要的行为(并隐藏了所有丑陋的东西)。然后,您的代码就可以使用该函数,并且看起来很好,可读性强(您可以尝试其他实现方法)

    托马什提到的丑陋的事情是1)可变状态,2)底层枚举数的操作。返回到并包括谓词保持时间的高阶函数将如下所示:

    module Seq =
        let takeUntil pred (xs : _ seq) = seq{
            use en = xs.GetEnumerator()
            let flag = ref true
            while !flag && en.MoveNext() do
                flag := not <| pred en.Current
                yield en.Current }
    
    seq{1..10} |> Seq.takeUntil (fun x -> x % 5 = 0)
    |> Seq.toList
    // val it : int list = [1; 2; 3; 4; 5]
    
    模块序列=
    设takeUntil pred(xs:uq)=seq{
    使用en=xs.GetEnumerator()
    让flag=ref为真
    while!flag&&en.MoveNext()执行
    标志:=不连续(乐趣x->x%5=0)
    |>序号:toList
    //val-it:int-list=[1;2;3;4;5]
    
    对于您的特定应用程序,您需要将DU的大小写映射到布尔值

    (migrators : seq<MigratorResult>)
    |> Seq.takeUntil (function Success _ -> false | Error _ -> true)
    
    (迁移器:seq)
    |>Seq.takeUntil(函数成功->假|错误->真)
    
    这实际上效果很好!我知道这将是一个带有累加器的函数,但没有意识到可以这样使用unfold。
    (migrators : seq<MigratorResult>)
    |> Seq.takeUntil (function Success _ -> false | Error _ -> true)