Как мне сделать функцию Haskell, которая генерирует уникальное значение каждый раз, когда она вызывается в ходе выполнения программы?
Одна идея:
incrementInteger :: IO (Integer)
incrementInteger = -- ...
так что он увеличивается каждый раз, когда он вызывается в ходе программы (независимо от того, из какого потока он вызывается и т. д.).
incrementIngeter
=> 0
incrementInteger
=> 1
incrementInteger
=> 2
Тем не менее, единственное свойство, которое меня волнует для этой функции, «несмотря ни на что, значение уникально при каждом вызове». Как это сделать?
Обновлено: Похоже, Данные.UUID предоставляет это через generatedNamed
.
«EDIT: похоже, что Data.UUID предоставляет это через generatedNamed
». Осторожный. Тот, который вы связали, - это UUID v5, что означает, что число основано на введенных вами данных. Это даст вам уникальные результаты, только если вы каждый раз будете указывать уникальное пространство имен и/или параметры объекта. Я не думаю, что это то, чего ты хочешь. Если вы хотите использовать UUID, попробуйте UUID v1, который использует ваш MAC-адрес и метку времени. Или просто используйте пакет время, чтобы получить фактическую метку времени.
Я бы, наверное, решил это сначала с помощью State Integer
или, если код уже находится в IO
, то написав оболочку для ReaderT (IORef Integer) IO
. По сравнению с глобальным счетчиком легче понять код, в котором явно указано, какие функции могут получать доступ и изменять значение.
Однако, если ничего не помогает, и вы действительно хотите, чтобы это было глобальным для программы, обычный способ небезопасный сделать это в GHC Haskell:
import Data.IORef
import System.IO.Unsafe (unsafePerformIO)
-- A global mutable counter
-- The NOINLINE is critical to ensure the counter is unique
counter :: IORef Integer
counter = unsafePerformIO (newIORef 0)
{-# NOINLINE counter #-}
-- Atomically increment the counter and return its current value
next :: IO Integer
next = atomicModifyIORef' counter (\ x -> (x + 1, x))
Data.Unique
в base
использует эту реализацию под капотом, но не предоставляет доступ к базовому целому числу. На Hackage также есть различные пакеты, обеспечивающие аналогичную генерацию уникальных идентификаторов — GUID, UUID и т. д.
Но зачем создавать свой собственный, если он уже входит в стандартную комплектацию компилятора?
@DanielWagner: Если свойство Только действительно имеет значение, так как значение уникально, то Data.Unique
совершенно нормально. (Черт возьми, для этого подойдет даже IORef ()
.) Если вы хотите Show
, сериализовать или иным образом манипулировать идентификатором, вам нужна реализация, которая предоставляет эти возможности.
Если вам действительно нужно, чтобы это был ввод-вывод, вы могли бы реализовать это на C с помощью FFI?