[英]F# How to avoid twice cast
let a = seq { yield Some 1; yield Some 2; yield Some 3; yield None }
a
|> Seq.takeWhile Option.isSome // cast 1
|> Seq.map Option.get // cast 2
|> Seq.iter (printfn "%A")
a
|> Seq.filter Option.isSome // cast 1
|> Seq.map Option.get // cast 2
|> Seq.iter (printfn "%A")
type AB =
| A of a : int
| B of b : string
let a = seq{
yield A 1
yield A 2
yield B "ds"
yield B "fsdf"
}
let (|As|Bs|) = function
| A _ -> As
| B _ -> Bs
let matcher = function
| A a-> printfn "%A" a
| B b -> printfn "%A" b
a
|> Seq.groupBy (|As|Bs|) // cast 1
|> Seq.map snd
|> Seq.iter (Seq.iter matcher) // cast 2
對於“案例2”,您可以將Seq.choose
與身份函數id
:
a
|> Seq.choose id
|> Seq.iter (printfn "%A")
Seq.choose
的文檔說
將給定函數應用於列表的每個元素,並返回由每個元素的結果組成的列表,其中函數返回帶有某些值的Some。
傳遞給它的身份函數將因此返回每個Some
Option
值的內容。
如果您使用列表,則可以在Haskell中執行相同的操作(從您的評論來看,您已經知道)。 F#還具有模式匹配,它的工作方式幾乎相同,除了該語言不是惰性的,因此您必須考慮到這一點。 例如:
let rec case2 xs =
match xs with
| (Some x)::rest -> printfn "%A" x; case2 rest
| None::rest -> case2 rest
| [] -> ()
(請注意:如果您要進行顯式遞歸,最好將其保留為“ tail”變量;由於懶惰,在Haskell中這無關緊要,但是在.NET中,如果不小心)
如果您要處理序列,情況會更加復雜。 對於某些事情,您可以使用計算表達式(它們與Haskell中的do
表示法有些相關):
let case2 xs = seq {
for x in xs do
match x with | Some a -> yield a | None -> ()
}
或在某些情況下,標准庫函數:
let case2 xs = Seq.choose id xs
(注意:由於值限制,無法對上述示例進行eta歸約)
但是您的第一個示例(“提前停止”)不能這樣聲明性地表示。 你仍然需要使用takeWhile
,但至少你可以再使用choose
,而不是map
,以避免使用部分功能:
let case1 xs = xs |> Seq.takeWhile Option.isSome |> Seq.choose id
如果您確實希望單個模式匹配而不是兩個模式匹配,則可以更深入一層並直接使用IEnumerable
接口:
let case1 (xs: seq<_>) = seq {
use e = xs.GetEnumerator()
let mutable stop = false
while not stop && e.MoveNext() do
match e.Current with
| Some x -> yield x
| None -> stop <- true
}
請注意,這使用可變的變量,乍一看看上去很難看,但值得記住的是,在.NET序列(又名IEnumerable<'t>
)上進行迭代是一個固有的基於突變的過程。 看上面: e.MoveNext()
調用更改了枚舉數e
的狀態。 如果您想下降到這個水平,則必須處理這個事實。
當然,我可以通過將其替換為遞歸來消除stop
變量:
let case1 (xs: seq<_>) = seq {
use e = xs.GetEnumerator()
let rec loop() = seq {
if e.MoveNext() then
match e.Current with
| Some x -> yield x; yield! loop()
| None -> ()
}
yield! loop()
}
但是,這很愚蠢:如果我願意處理可變的枚舉器,那么我不妨全力以赴。
至於您的第三個示例 -我什至不知道您在嘗試做什么。 或者,我確實了解它的作用,但我看不出擺脫第二場比賽意味着什么。 也許您可以說明如何在Haskell中做同樣的事情?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.