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)