F#匹配可能的通用列表或序列类型

时间:2017-01-18 01:26:55

标签: f#

我正在尝试弄清楚包含在rop结果中的泛型类型是否是列表。这就是我尝试的但是我遇到了错误。

let checkType (result : RopResult<'tSuccess, 'errors>) =
    match result with
    | Success (s, msg) ->
        match s with
        | :? [] -> // error here

样品

let isList<'s> () = true
let processList (ls : 'domain list) = true
let processType (s : 'domain) = true

let checkType (result : RopResult<'tSuccess, 'errors>) =
    match result with
    | Success (s, msg) ->
        match s with
        | s when isList<s>() -> processList s
        | _ -> processType s
    | Failure (x) -> false

3 个答案:

答案 0 :(得分:2)

我不确定我是否真的理解你的问题 一般来说,如果你有一些多态类型(比如你的([\s\S]*?))并且想要处理它的多态部分,那么F#中的一个好方法就是 将代码解压缩为包装代码和处理器代码,处理器代码通过处理器部件的高阶函数传递。

示例:

RopResult

type RopResult<'tSuccess, 'tError> =
    | Success of 'tSuccess
    | Error of 'tError

let checkType (process: 'tSuccess -> 'tResult) (result : RopResult<'tSuccess, 'tError>) =
    match result with
    | Success s -> process s |> Success
    | Error e -> Error e

然后你

let processList (ls : 'domain list) = true
let processType (s : 'domain) = true

答案 1 :(得分:2)

假设您想确定提供的值是否属于通用列表类型,您可以这样做:

let isList value =
    let valueType = value.GetType()
    match valueType.IsGenericType with
    |true -> valueType.GetGenericTypeDefinition() = typedefof<_ list>
    |false -> false

使用示例:

isList [5];;
val it : bool = true
isList ["a", "b"];;
val it : bool = true
isList "a";;
val it : bool = false

使用RopResult或更正式的Either之类的内容时,定义map函数会很有帮助。 map函数采用函数'a -> 'b,并为您提供在某个高架域中运行的函数,例如RopResult<'a,'c> -> RopResult<'b,'c>

这类似于List.map : ('a ->'b) -> 'a List -> 'b List

我们这样定义:

let map f v =
    match v with
    |Success sv -> Success (f sv)
    |Failure fv -> Failure (fv)

然后您可以在isList上使用RopResult,只需执行以下操作:

ropResult |> map isList

其他人在评论中警告您,一旦确定类型是否为列表,可能存在关于如何实际处理结果的潜在问题。具体而言,您需要确保processListprocessType函数的返回类型相同(尽管我建议您重新访问processType的命名并将其命名为processValue因为你没有按类型操作,我认为这个名字令人困惑。)

答案 2 :(得分:2)

我将首先解释如何使代码工作的技术细节,然后尝试说服您(与此线程中的其他人一样)可能不是解决问题的正确方法。

首先,您的匹配语句有语法错误。你可以写一下类型测试和演员阵容

match s with
| :? List<int> as theIntList -> ...do something with theIntList ...

当您将其添加到代码中时,F#编译器会抱怨“运行时强制或类型测试...涉及不确定类型....需要进一步的类型注释”。通过更具体地说明您的checkType处理的结果类型来解决这个问题:它是一些System.Object实例和消息,所以你要写:

let checkType (result : Result<obj*string, 'errors>) =
    match result with
    | Success (s, msg) ->
        match s with
        | :? List<int> as theIntList -> ... do something

请注意,您无法将其更改为List<_>这样的通用内容 - F#将一次性执行类型测试投射,因此不会知道要投射什么至。如果您尝试,则会看到警告:List<_>已被推断为List<obj>

说了这么多:使用obj并不是惯用的方式,正如其他人已经试图指出的那样。 @robkuz和@TheInnerLight的答案包含您所需要的一切:map函数,对各个结果类型进行操作的函数,然后可以很好地组合:

let map f x = 
    match x with
    | Success (s, msg) -> Success (f s, msg)
    | Failure f -> Failure f

// This will automatically be inferred to be of type Result<(int list * string), 'a>
let myFirstResult = Success ([1;2], "I've created an int list")
// This will automatically be inferred to be of type Result<(string list * string), 'a>
let mySecondResult = Success (["foo"; "bar"], "Here's a string list")
// Process functions for specific result types. No type tests needed!
let processIntList (l: int list) = Seq.sum l
let processStringList = String.concat "; "
// This will automatically be inferred to be of type Result<(int * string), 'a>
let mapFirst = myFirstResult |> map processIntList
// This will automatically be inferred to be of type Result<(string * string), 'a>
let mapSecond = mySecondResult |> map processStringList