Может ли F # заставить параметр быть байтом [8]? - PullRequest
3 голосов
/ 25 апреля 2011

Мне нужна небольшая служебная функция, которая генерирует контрольную сумму из массива из 8 байтов.

Теперь это само по себе тривиально, за исключением того, что я не могу использовать byte Checksum(byte[8] input) в C # в качестве объявления метода - я не могу указать размер массива, поэтому я должен использовать byte [], который может быть любого размера, и в теле метода мне нужно проверить, что входные данные не равны нулю и длина == 8.

Мне просто интересно, может ли F # сделать это? Я слышал, что у F # гораздо больше возможностей ограничить допустимые параметры для функции (например, Дискриминационные объединения)?

Конечно, в этом тривиальном примере F # будет излишним, но мне любопытно.

Ответы [ 4 ]

4 голосов
/ 25 апреля 2011

Если вы не хотите, чтобы вызывающий абонент передавал их по отдельности, аргумент byte[] в порядке IMO;единственное изменение, которое я хотел бы сделать, - это то, что я тоже рассмотрел бы передачу в начальном смещении (так как я часто работаю вдали от начала byte[] - но это зависит от вашего контекста).

Если вы действительно хотите избежать этого уродства, вы можете рассмотреть его как long (или, возможно, лучше (из-за сдвига вправо негативов) для битовой работы: ulong).Вы всегда знаете, что это ровно 8 байтов в длину, и это позволяет избежать нескольких загрузок.

Вы можете переключаться между двумя форматами либо путем сдвига, либо путем небезопасного преобразования byte* и ulong*

3 голосов
/ 25 апреля 2011

Я бы сказал, что правильным способом было бы создать type, который оборачивает байт [8], и использовать его в качестве параметра.


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

let (|Is8|NotIs8|) (input : byte[]) = if input.Length = 8 then Is8 else NotIs8


let testFunction (a : 'T[]) = 
    match a with
    | Is8 -> printfn "yes it is 8 in size"
    | NotIs8 ->  printfn "it is not 8 in size"
2 голосов
/ 25 апреля 2011

Ни один из двух языков не может указывать, что функция принимает массив определенной длины. Проблема в том, что проверить, действительно ли вызывающая сторона предоставляет массив такой длины, довольно сложно. Его можно проверить, когда массив создается напрямую с помощью new byte[8], но во всех других случаях требуются некоторые хитрые приемы.

Это частично делается с помощью Code Contracts , который является инструментом для дополнительной проверки, который можно установить в Visual Studio и использовать как с C #, так и с F #. Позволяет написать что-то вроде:

byte CheckSum(byte[] data) {
  Contract.Requires(data != null);
  Contract.Requires(data.Length == 8);
  // Implementation
}

Code Contracts поставляется с инструментом, который выдает предупреждение во время компиляции, когда вы вызываете CheckSum с массивом неправильного размера. Он также может генерировать проверку во время выполнения (когда он не может статически определить правильность вызова).

1 голос
/ 26 апреля 2011

В F # (или любом другом языке .NET) тип не может зависеть от значения, поэтому ответ - нет, вы не можете этого сделать.(Обратите внимание, что вы могли бы кодировать это в шаблоне C ++, поскольку шаблоны могут зависеть от целочисленных параметров.) Использование типа оболочки для byte [] просто сдвигает проверку длины времени выполнения на создание объекта оболочки и неЭто действительно не улучшит ситуацию.

Единственный способ навязать правильный тип во время компиляции, который я могу придумать, - использовать 8-кортеж (или эквивалентный тип с 8-байтовыми полями).Это, однако, кажется довольно уродливым решением, поскольку в конечном итоге оно требует, чтобы вы четко указали каждый из отдельных байтов.К счастью, уже есть примитивный тип, который удовлетворяет ограничению длины: ulong, как предложил Марк.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...