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

问题描述 投票:4回答:1

如何将标识符模式的结果复制为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

因为上面的teacherPerson类型,而不是string*int*int list。如果不更改printTeacher类型签名string*int*int list -> unit,我应该怎样做才能拥有更短的模式?

.net f# functional-programming pattern-matching
1个回答
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."
© www.soinside.com 2019 - 2024. All rights reserved.