我有一个表示原始类型的区分工会:
type Expr =
| Int of bigint
| Real of float
| Symbol of string
| Bool of bool
| List of Expr list
Run Code Online (Sandbox Code Playgroud)
我正在编写一个函数list : obj list -> Expr list
,该函数将检查对象的类型并将其相应地转换为Expr
:
let rec list : (obj list -> Expr list) = function
| head::tail ->
match head with
| :? string as x'-> Symbol (x') :: list tail
| :? int as x'-> Int(bigint x') :: list tail
| :? bigint as x' -> Int x' :: list tail
| :? bool as x' -> Bool x' :: list tail
| :? float as x' -> Real x' :: list tail
| :? Expr as x' -> x' :: list tail
| :? list<obj> as x' -> List(list x') :: list tail
| _ -> []
Run Code Online (Sandbox Code Playgroud)
在| :? list<obj> as x' -> List(list x') :: list tail
像这样的嵌套列表上调用此函数时,大小写似乎不匹配:list [1;[2;1]]
这可以完美编译,但会返回错误,指出匹配的大小写不完整,似乎正在尝试处理大小写list<int>
,但事实并非如此找不到它。我希望list<obj>
可以匹配任何类型的列表,'a
但事实并非如此。我应该写什么模式来匹配任何类型的列表?该功能非常适合对象的非嵌套列表。
您无法使用模式匹配来检查对象是否是具有未指定泛型参数的泛型类型的值。您可以检查它是否是list<int>
或list<obj>
,但它必须是正是这种类型-所以list<int>
,当你使用检查一个类型不匹配:? list<obj>
(也,你可以写:? list<_>
,但是编译器将只需填写_
用obj
)
如果只关心集合,则可以使用System.Collections.IEnumerable
所有集合(列表,数组等)实现的非通用接口:
let rec list : (obj list -> Expr list) = function
| head::tail ->
match head with
| :? string as x'-> Symbol (x') :: list tail
// Other cases you're already covering
| :? float as x' -> Real x' :: list tail
| :? Expr as x' -> x' :: list tail
| :? System.Collections.IEnumerable as x' ->
// It is a collection and we can get its elements as `obj` values!
let nested = x' |> Seq.cast |> List.ofSeq |> list
List(nested) :: list tail
| _ -> []
Run Code Online (Sandbox Code Playgroud)