F#:如何优雅地选择和分组受歧视的工会? [英] F#: how to elegantly select and group discriminated unions?

查看:70
本文介绍了F#:如何优雅地选择和分组受歧视的工会?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

说我有一个形状列表:

type shape = 
| Circle of float
| Rectangle of float * float

let a = [ Circle 5.0; Rectangle (4.0, 6.0)]

然后我该如何测试一个圆存在吗?我可以为每个形状创建一个函数

How can I then test e.g. a Circle exists in a? I could create a function for each shape

let isCircle s = 
    match s with
    | Circle -> true
    | _ -> false
List.exists isCircle a

但是我觉得F#中必须有一种更优雅的方式,除了必须为每种形状类型定义这样的功能.有吗?

but I feel there must be a more elegant way in F#, other than having to define such a function for each shape type. Is there?

相关的问题是如何根据形状类型对形状列表进行分组:

Related question is how to group a list of shapes, based on shape types:

a |> seq.groupBy( <shapetype? >)

推荐答案

您可以将F#反射与引号结合使用以获得通用解决方案

you can combine F# reflection with quotations to get generic solution

open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns

type Shape = 
    | Circle of float
    | Rectangle of float * float

let isUnionCase (c : Expr<_ -> 'T>)  = 
    match c with
    | Lambda (_, NewUnionCase(uci, _)) ->
        let tagReader = Microsoft.FSharp.Reflection.FSharpValue.PreComputeUnionTagReader(uci.DeclaringType)
        fun (v : 'T) -> (tagReader v) = uci.Tag
    | _ -> failwith "Invalid expression"

let a = 
    [ Circle 5.0; Rectangle (4.0, 6.0)] 
        |> List.filter (isUnionCase <@ Rectangle @>)
printf "%A" a

这篇关于F#:如何优雅地选择和分组受歧视的工会?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆