Как запретить этой циклической полиномиальной хеш-функции использовать ограничение типа?
Я пытаюсь реализовать циклическую полиномиальную хэш-функцию в F#. Он использует побитовые операторы ^^^ и <<<. Вот пример функции, которая хэширует массив:
let createBuzhash (pattern : array<'a>) =
let n = pattern.Length
let rec loop index pow acc =
if index < n then
loop (index+1) (pow-1) (acc ^^^ ((int pattern.[index]) <<< pow))
else
acc
loop 0 (n-1) 0
Моя проблема в том, что тип 'a
будет ограничен int
в то время как я хочу, чтобы эта функция работала с любыми типами, которые работают с побитовыми операторами, например char
, Я пытался с помощью inline
, но это создает некоторые проблемы в моей библиотеке. Есть ли способ исправить это без использования inline
?
Правка для ясности: эта функция будет частью библиотеки, а для типов, не поддерживающих побитовые операторы, предусмотрена другая хеш-функция. Я хочу, чтобы эта функция работала с массивами числовых типов и / или символов.
Редактировать 2 (проблема решена): проблема с inline была в том, как я загружал функцию из моей библиотеки. вместо
let hashedPattern = library.createBuzhash targetPattern
Я использовал эту привязку:
let myFunction = library.createBuzhash
let hashedPattern = myFunction targetPattern
что ограничивает тип ввода для myFunction
к инт, хотя createBuzhash
функция является inline
функция в библиотеке. Изменение способа вызова функции решило проблему ограничения типа и inline
работает отлично, как предполагает ответ ниже.
1 ответ
В реализации вы конвертируете значение в массиве в целое число, используя int
функционировать следующим образом: int pattern.[index]
Это создает ограничение на тип элементов массива, требующих, чтобы они были "чем-то, что может быть преобразовано в int
". Если вы отметите функцию как inline
, это на самом деле будет работать для таких типов, как char
и вы сможете написать:
createBuzhash [|'a'; 'b'|]
Но есть еще много других типов, которые не могут быть преобразованы в целое число с помощью int
функция.
Чтобы заставить это работать для любого типа, вы должны решить, как вы хотите обрабатывать типы, которые не являются числовыми. Хотите ли вы:
- Предоставить свою собственную функцию хеширования для всех значений?
- Используйте встроенный.NET
GetHashCode
операция? - Заставить вашу функцию работать только с числовыми типами и массивами числовых типов?
Один из вариантов - добавить параметр, который указывает, как выполнить преобразование:
let inline createBuzhash conv (pattern : array<'a>) =
let n = pattern.Length
let rec loop index pow acc =
if index < pattern.Length then
loop (index+1) (pow-1) (acc ^^^ ((conv pattern.[index]) <<< pow))
else
acc
loop 0 (n-1) 0
При звонке createBuzhash
Теперь вам нужно дать ему функцию для хэширования элементов. Это работает на примитивных типах, используя int
функция:
createBuzhash int [| 0 .. 10 |]
createBuzhash int [|'a'; 'b'|]
Но вы также можете использовать встроенный механизм хеширования F#:
createBuzhash hash [| (1,"foo"); (2,"bar") |]
И вы даже можете обрабатывать вложенные массивы, передавая функцию себе:
createBuzhash (createBuzhash int) [| [| 1 |]; [| 2 |] |]