Генерировать уникальные значения при каждом вызове функции?

Как мне сделать функцию Haskell, которая генерирует уникальное значение каждый раз, когда она вызывается в ходе выполнения программы?

Одна идея:

incrementInteger :: IO (Integer)
incrementInteger = -- ...

так что он увеличивается каждый раз, когда он вызывается в ходе программы (независимо от того, из какого потока он вызывается и т. д.).

incrementIngeter
=> 0

incrementInteger
=> 1

incrementInteger
=> 2

Тем не менее, единственное свойство, которое меня волнует для этой функции, «несмотря ни на что, значение уникально при каждом вызове». Как это сделать?

Обновлено: Похоже, Данные.UUID предоставляет это через generatedNamed.

Если вам действительно нужно, чтобы это был ввод-вывод, вы могли бы реализовать это на C с помощью FFI?

AJF 10.04.2019 00:02

«EDIT: похоже, что Data.UUID предоставляет это через generatedNamed». Осторожный. Тот, который вы связали, - это UUID v5, что означает, что число основано на введенных вами данных. Это даст вам уникальные результаты, только если вы каждый раз будете указывать уникальное пространство имен и/или параметры объекта. Я не думаю, что это то, чего ты хочешь. Если вы хотите использовать UUID, попробуйте UUID v1, который использует ваш MAC-адрес и метку времени. Или просто используйте пакет время, чтобы получить фактическую метку времени.

DarthFennec 10.04.2019 00:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
2
207
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Пакет base предлагает для этой цели newUnique. (Обратите внимание: эти значения будут уникальными в рамках одного запуска программы, но не обязательно между запусками.)

Я бы, наверное, решил это сначала с помощью 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 и т. д.

Но зачем создавать свой собственный, если он уже входит в стандартную комплектацию компилятора?

Daniel Wagner 10.04.2019 01:21

@DanielWagner: Если свойство Только действительно имеет значение, так как значение уникально, то Data.Unique совершенно нормально. (Черт возьми, для этого подойдет даже IORef ().) Если вы хотите Show, сериализовать или иным образом манипулировать идентификатором, вам нужна реализация, которая предоставляет эти возможности.

Jon Purdy 10.04.2019 01:56

Другие вопросы по теме