是否已经有办法做一些像a chooseTill或a 这样的事情foldTill,直到收到None选项才会处理?实际上,任何具有"until"选项的高阶函数.当然,对于像地图这样的东西没有任何意义,但我发现我经常需要这种东西而且我想确保我没有重新发明轮子.
一般来说,写这样的东西很容易,但我很好奇是否已经有办法做到这一点,或者是否存在于某个已知的库中?
let chooseTill predicate (sequence:seq<'a>) =
seq {
let finished = ref false
for elem in sequence do
if not !finished then
match predicate elem with
| Some(x) -> yield x
| None -> finished := true
}
let foldTill predicate seed list =
let rec foldTill' acc = function
| [] -> acc
| (h::t) -> match predicate acc h with
| Some(x) -> foldTill' x t
| None -> acc
foldTill' seed list
let (++) a b = a.ToString() + b.ToString()
let abcdef = foldTill (fun acc v ->
if Char.IsWhiteSpace v then None
else Some(acc ++ v)) "" ("abcdef ghi" |> Seq.toList)
// result is "abcdef"
Run Code Online (Sandbox Code Playgroud)
Tom*_*cek 12
我认为,可以通过组合得到,可以轻松地Seq.scan和Seq.takeWhile:
open System
"abcdef ghi"
|> Seq.scan (fun (_, state) c -> c, (string c) + state) ('x', "")
|> Seq.takeWhile (fst >> Char.IsWhiteSpace >> not)
|> Seq.last |> snd
Run Code Online (Sandbox Code Playgroud)
这个想法是Seq.scan做的事情Seq.fold,但不是等待最终结果,而是产生中间状态.然后,您可以继续使用中间状态,直到结束.在上面的示例中,state是当前字符和连接字符串(以便我们可以检查字符是否为空格).
基于返回函数的更通用版本option可能如下所示:
let foldWhile f initial input =
// Generate sequence of all intermediate states
input |> Seq.scan (fun stateOpt inp ->
// If the current state is not 'None', then calculate a new one
// if 'f' returns 'None' then the overall result will be 'None'
stateOpt |> Option.bind (fun state -> f state inp)) (Some initial)
// Take only 'Some' states and get the last one
|> Seq.takeWhile Option.isSome
|> Seq.last |> Option.get
Run Code Online (Sandbox Code Playgroud)