是否可以让一个函数从不同的记录类型中调用相同的标签?例如,假设有两条记录,定义如下
type Pen = {
Diameter: float
InkColor: string
}
type Pencil = {
Diameter: float
Hardness: int
Blackness: int
}
我可以创建一个函数来从任一记录类型访问Diameter标签吗?现在,如果我定义一支钢笔和铅笔,编译器会对使用哪种记录类型感到困惑。问题是我不希望编译器选择一种类型,如果确实选择了某种类型,则允许使用这两种类型。这个例子不会编译,因为它需要一支铅笔。
let black_pen = {
Diameter = 0.7
InkColor = "Black"
}
let mechanical_pencil = {
Diameter = 0.5
Hardness = 1
Blackness = 2
}
let getDiameter writing_utility =
let {Diameter = dia} = writing_utility
dia
printf "%A" (getDiameter black_pen)
我现在看到的唯一选择是:
如果我可以使用泛型来做这样的事情会很好:
let getDiameter writing_utility =
let {Diameter<float> = dia} = writing_utility
dia
只要记录有一个标签“Diameter”并且是一个浮点数,它就会返回该值。
答案 0 :(得分:5)
你真的应该使用继承,但以下工作
let inline getDiameter (t:^q when ^q :( member Diameter:float)) =
(^q : (member Diameter:float) t);;
答案 1 :(得分:2)
以下几个选项。
提供从“具有直径的东西”到“直径”的映射作为函数:
let getDiameter (util:'a) (diamFunc:'a->float) =
let dia = diamFunc util
dia
getDiameter black_pen (fun x -> x.Diameter)
getDiameter mechanical_pencil (fun x -> x.Diameter)
或者更干净,使用DU(很好地使用F#3.1命名为DU字段语法):
type WritingImplement =
| Pen of diameter:float * inkColor:string
| Pencil of float * int * int // 3.0 syntax
let black_pen = Pen(diameter = 0.7, inkColor = "Black")
let mechanical_pencil = Pencil(0.5, 1, 2) // 3.0 syntax
let getDiameter = function
| Pen(diameter = d) -> d
| Pencil(d, _, _) -> d // 3.0 syntax
答案 2 :(得分:2)
考虑getDiameter
做什么。它将something
映射到float
,即'a -> float
,但它没有意义,因为'a
表示它可以是任何内容,并将任何内容映射到float
值了解它的一些事情是行不通的。我们需要确保我们知道有关传递的东西的一些属性来获取float
值,即我们想要类似<something with Diameter> -> float
的东西,并且表示对某些东西的约束的最佳方式是使用接口,使得签名现在变为IWithDiameter -> float
。