I am trying to implement the Cyclic polynomial hash function in f#. It uses the bit-wise operators ^^^ and <<<. Here is an example of a function that hashes an array:
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
My problem is that the type of 'a
will be constrained to an int
, while i want this function to work with any of the types that work with bit-wise operators, for example a char
. I tried using inline
, but that creates some problems farther down in my library. Is there a way to fix this without using inline
?
Edit for clarity: The function will be part of a library, and another hash function is provided for types that don't support the bit-wise operators. I want this function to work with arrays of numeric types and/or chars.
Edit 2 (problem solved) : The problem with inline was the way how i loaded the function from my library. instead of
let hashedPattern = library.createBuzhash targetPattern
I used this binding:
let myFunction = library.createBuzhash
let hashedPattern = myFunction targetPattern
that constraints the input type for myFunction
to int, although the createBuzhash
function is an inline
function in the library. Changing the way I call the function fixed the type constraint problem, and inline
works perfectly fine, as the answer below suggests.
In the implementation, you are converting the value in the array to an Integer using the int
function as follows: int pattern.[index]
This creates a constraint on the type of array elements requiring them to be "something that can be converted to int
". If you mark the function as inline
, it will actually work for types like char
and you'll be able to write:
createBuzhash [|'a'; 'b'|]
But there are still many other types that cannot be converted to integer using the int
function.
To make this work for any type, you have to decide how you want to handle types that are not numeric. Do you want to:
GetHashCode
operation?One option would be to add a parameter that specifies how to do the conversion:
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
When calling createBuzhash
, you now need to give it a function for hashing the elements. This works on primitive types using the int
function:
createBuzhash int [| 0 .. 10 |]
createBuzhash int [|'a'; 'b'|]
But you can also use built-in F# hashing mechanism:
createBuzhash hash [| (1,"foo"); (2,"bar") |]
And you can even handle nested arrays by passing the function to itself:
createBuzhash (createBuzhash int) [| [| 1 |]; [| 2 |] |]