Почему параметр seq option
?
Одной из возможных причин для типа option
в параметре является необязательные параметры в методе без каррирования (т. Е. В стиле кортежа). Если у вас есть параметр, объявленный как ?param
, то он будет иметь тип Foo option
, где Foo - это «нормальный» тип param
(то есть тип, которым он был бы, если бы он не был необязательным параметром). ). Это позволяет вам писать код, подобный следующему (пример, дословно скопированный из документов MSDN):
type DuplexType =
| Full
| Half
type Connection(?rate0 : int, ?duplex0 : DuplexType, ?parity0 : bool) =
let duplex = defaultArg duplex0 Full
let parity = defaultArg parity0 false
let mutable rate = match rate0 with
| Some rate1 -> rate1
| None -> match duplex with
| Full -> 9600
| Half -> 4800
do printfn "Baud Rate: %d Duplex: %A Parity: %b" rate duplex parity
let conn1 = Connection(duplex0 = Full)
let conn2 = Connection(duplex0 = Half)
let conn3 = Connection(300, Half, true)
Здесь дополнительные параметры находятся в конструкторе типа Connection
, но вы можете увидеть, как они работают. Что касается вашего конкретного вопроса о seq option
параметрах, мне придется немного настроить пример документации MSDN, чтобы продемонстрировать разницу. Если один из этих необязательных параметров был последовательностью (скажем, последовательностью целых чисел, представляющих предпочтительные ставки и скорости восстановления), то вот как это может выглядеть с необязательными параметрами и без них:
type Connection(?rates : seq<int>) = // Final type will be `seq<int> option`
let realRates = defaultArg rates Seq.empty
let chosenRate = realRates |> Seq.find (fun r -> ...)
type ConnectionB(rates : seq<int>) = // Final type will be `seq<int>`
let chosenRate = rates |> Seq.find (fun r -> ...)
let conn1 = Connection() // Equivalent to passing `Seq.empty`
let conn2 = Connection(Seq.empty)
let conn3 = ConnectionB() // Compiler error; this is not allowed
let conn4 = ConnectionB(Seq.empty)
Использование необязательного параметра для seq позволяет вызывающей стороне пропускать указание этого параметра, что в некоторых случаях может сделать ваш API более привлекательным для использования. Так что это может быть одной из причин использовать seq option
в параметре. В других случаях это не имеет смысла; все зависит от того, как вы хотите, чтобы ваш API смотрел на внешний код.
А как насчет #
в объявлении типа?
Что касается вашего вопроса о символе #
, он называется в документации MSDN гибких типов , и это сокращение для ограничения типа: объявление типа #Foo
аналогично объявлению введите 'T when 'T :> Foo
. Конкретное преимущество использования #seq
состоит в том, что F # обычно неявно автоматически выполняет приведение между совместимыми типами и требует явного преобразования в ситуациях, подобных следующим (снова пример, дословно взятый из документов MSDN):
let iterate1 (f : unit -> seq<int>) =
for e in f() do printfn "%d" e
let iterate2 (f : unit -> #seq<int>) =
for e in f() do printfn "%d" e
// Passing a function that takes a list requires a cast.
iterate1 (fun () -> [1] :> seq<int>)
// Passing a function that takes a list to the version that specifies a
// flexible type as the return value is OK as is.
iterate2 (fun () -> [1])