将标识符模式与“as”模式相结合

时间:2017-12-23 11:41:02

标签: .net f# functional-programming pattern-matching

如何将标识符模式的结果复制为as模式以生成元组?

我的问题很困惑,所以我创建了一个例子,我想要打印这个人的信息,无论是教师还是学生:

type Person =
    | Teacher of name: string * age: int * classIds: int list
    | Student of name: string

let printTeacher (name, age, classIds) =
    printfn "Teacher: %s; Age: %d; Classes: %A" name age classIds

let print = function
    | Teacher (name, age, classIds) -> printTeacher (name, age, classIds)
    | Student name -> printfn "Student: %s" name

匹配模式很长且重复:

| Teacher (name, age, classIds) -> printTeacher (name, age, classIds)

所以我尝试使用as模式缩短它,但失败了:

| Teacher ((_, _, _) as teacher) -> printTeacher teacher

因为上述teacher具有Person类型,而不是string*int*int list。如何在不更改printTeacher类型签名string*int*int list -> unit的情况下缩短模式?

1 个答案:

答案 0 :(得分:3)

我能想到的一种方法是改变Teacher构造函数的定义:

type Person =
    | Teacher of items: (string * int * int list)
    | Student of name: string

let printTeacher (name, age, classIds) =
    printfn "Teacher: %s; Age: %d; Classes: %A" name age classIds

let print = function
    //| Teacher (name, age, classIds) -> printTeacher (name, age, classIds) // Still works
    | Teacher items -> printTeacher items
    | Student name -> printfn "Student: %s" name

通过更改Teacher以获取显式元组,您可以按名称引用它,但另一种方式仍可以正常工作。

但是,您失去了为元组项目命名的功能。

如果您不想或不能更改类型定义,另一种方法是为Teacher构造函数引入活动模式:

type Person =
    | Teacher of name: string * age: int * classIds: int list
    | Student of name: string

// Active pattern to extract Teacher constructor into a 3-tuple.
let (|TeacherTuple|_|) = function
| Teacher (name, age, classIds) -> Some (name, age, classIds)
| _ -> None

let printTeacher (name, age, classIds) =
    printfn "Teacher: %s; Age: %d; Classes: %A" name age classIds

let print = function
    | TeacherTuple items -> printTeacher items
    | Student name -> printfn "Student: %s" name
    // To make the compiler happy. It doesn't know that the pattern matches all Teachers.
    | _ -> failwith "Unreachable."