F # возвращает указанный тип объединения из массива байтов

Я пытаюсь написать функцию, которая принимает массив байтов и преобразует его в ADT, как указано параметром. Возможно ли это в F#? Это мой АТД:

type DataFormat =
    | Alphanumeric of string
    | Angle16 of float
    | Angle32 of float
    | Int16 of int
    | Int32 of int

Я пробовал около десяти различных способов форматирования спецификации функции, но не могу понять... Я прочитал некоторые другие сообщения на SO, такие как этот, что заставляет меня думать, что это сложнее, чем я думаю. Это были мои последние две попытки, которые, похоже, ни к чему не привели.

// 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‹>, но это, похоже, возвращает только базовый базовый тип.


person Eric    schedule 24.04.2015    source источник
comment
Можете ли вы привести пример пары ввода/вывода? Я действительно понятия не имею, что вы хотите делать с b там (поскольку вы просто игнорируете его) - помимо этого вы можете использовать match для сопоставления типов/классов во время выполнения с помощью оператора :?, но я не думаю, что это что ты пытаешься сделать   -  person Random Dev    schedule 24.04.2015
comment
Я отредактировал код, надеюсь, это поможет. Я пытался опустить фактическую работу по преобразованию байтов, выполняемую в различных ветвях, чтобы избежать путаницы...   -  person Eric    schedule 24.04.2015
comment
Я думаю, что знаю, что вы пытаетесь сделать, но я думаю, что в этом случае я бы предпочел вместо этого написать 5 разных версий вашей функции преобразования.   -  person Random Dev    schedule 25.04.2015
comment
другая идея может состоять в том, чтобы пометить байты по мере их создания — вы можете использовать ADT с одним регистром или даже фантомные типы для этого   -  person Random Dev    schedule 25.04.2015


Ответы (1)


Я думаю, что вы пытаетесь дважды использовать свой дискриминационный союз здесь.

Использование 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: вы используете союз как настоящий АТД. Тогда это будет возвращаемое значение вашей функции:

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)

Если вам не нравится способ явного написания ожидаемого типа с некоторым фальшивым содержимым данных, вы можете выбрать простое решение, подобное этому:

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. Поэтому, если вы планируете указывать типы сообщений с помощью композиции, вы можете использовать этот факт в своих интересах.

person BitTickler    schedule 24.04.2015
comment
Я понимаю ваш третий вариант, потому что я пробовал его, но для этого требуется что-то вроде этого в коде: let converted = readExpected byteArray Int(0), чтобы его вызвать, правильно? Казалось не совсем правильным создавать поддельный объект (т.е. Int(0)) для передачи в функцию, чтобы она могла выполнять сопоставление с образцом, но если это то, что нужно, возможно, это работает нормально. - person Eric; 25.04.2015
comment
@Eric уточненный ответ в этом аспекте - person BitTickler; 25.04.2015
comment
@Eric На самом деле я вижу здесь только две ситуации: 1. Вы знаете, что содержит data[], когда вызываете функцию (или, по крайней мере, ожидаете знать). 2. У вас есть информация о том, что будет дальше, в самом массиве данных, и у вашего вызывающего абонента нет никаких ожиданий. Для ситуации 1 вы также можете напрямую вызвать нужную вам функцию. - person BitTickler; 25.04.2015
comment
Отлично, спасибо, что дали ему немного глаз. Это, по крайней мере, дало мне проверку здравомыслия, что я не пропустил какое-то явно простое выражение сопоставления с образцом! - person Eric; 25.04.2015