3

Is it possible to have one function call the same label from different record types? For example lets say there are two records, defined below

type Pen = {
    Diameter: float
    InkColor: string
}

type Pencil = {
    Diameter: float
    Hardness: int
    Blackness: int
}

Can I make a function to access the Diameter label from either record type? Right now if I define a pen and pencil, the compiler is confused on which record type to use. Problem is I don't want the compiler to pick a type, of if it does pick something, allow the use of both types. The example wont compile because it expects a pencil.

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)

My only options I see now are:

  1. Combine the records with an enumerated type to tell which is what object. Then pattern match
  2. Use classes instead to use inherit
  3. Use a dynamic type and reflection to check the label and type

It would be nice if I could use generics for something like this:

let getDiameter writing_utility = 
    let {Diameter<float> = dia} = writing_utility
    dia

This was as long as the record has a label "Diameter" and is a float, it will return the value.

4

3 回答 3

5

你真的应该为此使用继承,但以下工作

let inline getDiameter (t:^q when ^q :( member Diameter:float)) = 
    (^q : (member Diameter:float) t);; 
于 2013-08-07T02:52:32.493 回答
2

想想getDiameter做什么。它映射somethingfloatie 'a -> float,但它没有意义,因为这'a意味着它可以是任何东西,并且在不了解它的情况下将任何东西映射到float价值是行不通的。我们需要确保我们知道传递的东西的一些属性来获取float值,即我们想要类似的东西<something with Diameter> -> float,并且表示对某物的约束的最佳方法是使用接口,使得签名现在变为IWithDiameter -> float.

于 2013-08-07T08:26:01.400 回答
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
于 2013-08-07T06:31:44.550 回答