F# return 来自字节数组的指定联合类型
F# return a specified union type from byte array
我正在尝试编写一个接受字节数组并将其转换为参数指定的 ADT 的函数。这在 F# 中可能吗?这是我的 ADT:
type DataFormat =
| Alphanumeric of string
| Angle16 of float
| Angle32 of float
| Int16 of int
| Int32 of int
我已经尝试了大约十种不同的方法来格式化函数规范,但我无法弄清楚...我阅读了 SO 上的其他一些帖子,例如 this one 这让我想到了这个比我想象的要复杂。这是我最后两次尝试,但似乎没有任何结果。
// Attempt #1
// This function would require that I pass in a shell
// object as the "format" parameter to make it work, like:
// let converted = fromBytes1 myArray Angle16(0.0)
let fromBytes1 (b : byte[]) (format : DataFormat) =
match format with
| Alphanumeric -> Alphanumeric(BitConverter.ToString(b))
| Angle16 -> // convert 2-bytes into float...omitted
| Angle32 -> Angle32(float (BitConverter.ToSingle(b,0)))
// Attempt #2
// the 'T seems to only specify the underlying type like (float, int)
let fromBytes2<'T> (b : byte[]) =
match 'T with
| Alphanumeric -> Alphanumeric(BitConverter.ToString(b))
| Angle16 -> // convert 2-bytes into float...omitted
| Angle32 -> Angle32(float (BitConverter.ToSingle(b,0)))
我也尝试过使用 typeof<>,但这似乎只是 return 底层基本类型。
我认为你试图在这里双重使用你的受歧视的联盟。
用途 1:您将其用作标记(或 erlang 术语中的原子)以向函数指示您的期望。然后,它看起来像这样:
type DataType = | Int | Bool // without any data items associated.
let readExpected (valueType : DataType) (data : byte[] ) =
match valueType with
| DataType.Int -> // parse the int from data and do something with it
| DataType.Bool -> // parse the boolean representation from data ...
用途2:你把union当做真正的ADT。那么它将是您函数的 return 值:
type ADT = | Int of int | Bool of bool // now they have data
let read (data : byte[]) : ADT =
let wireType = data.[0]
match wireType with
| 2uy -> Int(readInt data) // return the parsed int as ADT.Int
| 3uy -> Bool(readBool data) // return the parsed bool as ADT.Bool
| _ -> failwith "Unknown wire type in data."
当然,您可以尝试混合使用这两种方法。
type ADT = | Int of int | Bool of bool // now they have data
let readExpected (data : byte[]) (expectedType : ADT) : ADT =
match expectedType with
| Int(_) -> Int(readInt data)
| Bool(_) -> Bool(readBool data)
如果您不喜欢用一些虚假数据内容显式编写 expectedType 的方式,您可以选择像这样的简单解决方案:
type ADT = | Int of int | Bool of bool // now they have data
let IntType = Int(0)
let BoolType = Bool(false)
let readExpected (data : byte[]) (expectedType : ADT) : ADT =
match expectedType with
| Int(_) -> Int(readInt data)
| Bool(_) -> Bool(readBool data)
// caller code:
let intValue = readExpected data IntType
let boolValue = readExpected data BoolType
也许在这里调换两个参数的顺序是有意义的。
如果实际上不是动态的,那么不假装它是动态的也许是有道理的。
如果调用者能够在上面的代码中指定 IntType
,您也可以简单地为每种类型创建一个函数。
type ADT = | Int of int | Bool of bool // now they have data
let readInt data =
Int( foo data) // foo data is my lazy way of saying: However you parse it ;)
let readBool data =
Bool( if data.[0] = 0uy then false else true )
// caller code:
let intValue = readInt data
let boolValue = readBool data
请注意,所有这些 readXXX 函数都具有相同的类型:byte[] -> ADT
。因此,如果您计划通过组合的方式指定消息类型,您可以利用这一事实来发挥自己的优势。
我正在尝试编写一个接受字节数组并将其转换为参数指定的 ADT 的函数。这在 F# 中可能吗?这是我的 ADT:
type DataFormat =
| Alphanumeric of string
| Angle16 of float
| Angle32 of float
| Int16 of int
| Int32 of int
我已经尝试了大约十种不同的方法来格式化函数规范,但我无法弄清楚...我阅读了 SO 上的其他一些帖子,例如 this one 这让我想到了这个比我想象的要复杂。这是我最后两次尝试,但似乎没有任何结果。
// Attempt #1
// This function would require that I pass in a shell
// object as the "format" parameter to make it work, like:
// let converted = fromBytes1 myArray Angle16(0.0)
let fromBytes1 (b : byte[]) (format : DataFormat) =
match format with
| Alphanumeric -> Alphanumeric(BitConverter.ToString(b))
| Angle16 -> // convert 2-bytes into float...omitted
| Angle32 -> Angle32(float (BitConverter.ToSingle(b,0)))
// Attempt #2
// the 'T seems to only specify the underlying type like (float, int)
let fromBytes2<'T> (b : byte[]) =
match 'T with
| Alphanumeric -> Alphanumeric(BitConverter.ToString(b))
| Angle16 -> // convert 2-bytes into float...omitted
| Angle32 -> Angle32(float (BitConverter.ToSingle(b,0)))
我也尝试过使用 typeof<>,但这似乎只是 return 底层基本类型。
我认为你试图在这里双重使用你的受歧视的联盟。
用途 1:您将其用作标记(或 erlang 术语中的原子)以向函数指示您的期望。然后,它看起来像这样:
type DataType = | Int | Bool // without any data items associated.
let readExpected (valueType : DataType) (data : byte[] ) =
match valueType with
| DataType.Int -> // parse the int from data and do something with it
| DataType.Bool -> // parse the boolean representation from data ...
用途2:你把union当做真正的ADT。那么它将是您函数的 return 值:
type ADT = | Int of int | Bool of bool // now they have data
let read (data : byte[]) : ADT =
let wireType = data.[0]
match wireType with
| 2uy -> Int(readInt data) // return the parsed int as ADT.Int
| 3uy -> Bool(readBool data) // return the parsed bool as ADT.Bool
| _ -> failwith "Unknown wire type in data."
当然,您可以尝试混合使用这两种方法。
type ADT = | Int of int | Bool of bool // now they have data
let readExpected (data : byte[]) (expectedType : ADT) : ADT =
match expectedType with
| Int(_) -> Int(readInt data)
| Bool(_) -> Bool(readBool data)
如果您不喜欢用一些虚假数据内容显式编写 expectedType 的方式,您可以选择像这样的简单解决方案:
type ADT = | Int of int | Bool of bool // now they have data
let IntType = Int(0)
let BoolType = Bool(false)
let readExpected (data : byte[]) (expectedType : ADT) : ADT =
match expectedType with
| Int(_) -> Int(readInt data)
| Bool(_) -> Bool(readBool data)
// caller code:
let intValue = readExpected data IntType
let boolValue = readExpected data BoolType
也许在这里调换两个参数的顺序是有意义的。
如果实际上不是动态的,那么不假装它是动态的也许是有道理的。
如果调用者能够在上面的代码中指定 IntType
,您也可以简单地为每种类型创建一个函数。
type ADT = | Int of int | Bool of bool // now they have data
let readInt data =
Int( foo data) // foo data is my lazy way of saying: However you parse it ;)
let readBool data =
Bool( if data.[0] = 0uy then false else true )
// caller code:
let intValue = readInt data
let boolValue = readBool data
请注意,所有这些 readXXX 函数都具有相同的类型:byte[] -> ADT
。因此,如果您计划通过组合的方式指定消息类型,您可以利用这一事实来发挥自己的优势。