Как выбрать случайный элемент списка в чистой функции?

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

randomPick :: [a] -> a 

Что мне делать?

21
задан Bartek Banachewicz 11 June 2014 в 09:04
поделиться

3 ответа

То, что вы описали, невозможно сделать в чистом функциональном коде.

Чистый функциональный код подразумевает, что вы всегда будете получать один и тот же результат для одного и того же ввода. Поскольку функция рандомизации по определению дает вам разные выходные данные для одного и того же входа, это невозможно в чистом функциональном коде.

Если вы не передадите дополнительное значение, как описано в ответе @ camccann . Технически он даже не должен быть таким продвинутым, как ГСЧ, в зависимости от ваших потребностей. Вы можете передать целое число, умножить его на 10 и вычесть 3 (или что-то еще), а затем взять его по модулю, чтобы найти свой индекс. Тогда ваша функция останется чистой, но вы напрямую контролируете случайность.

Другой вариант - использовать RandomRIO для генерации числа в диапазоне, которое затем можно использовать для выбора индекса из списка. Это потребует от вас входа в монаду ввода-вывода.

23
ответ дан 29 November 2019 в 06:42
поделиться

Если вы хотите использовать генераторы случайных чисел в чисто функциональном коде, но не должны явно передавать состояние генератора, вы можете использовать монаду состояний (или преобразователь монад) и скрыть связь. Монады состояний по-прежнему прозрачны по ссылкам, и уйти от монады состояний безопасно и нормально. Вы также можете использовать монаду ST, если хотите истинное локальное изменяемое состояние, которое чисто функционально снаружи.

Вот полезный код, который я написал и иногда использую:

rand :: (Random a, RandomGen g, MonadState g m) => a -> a -> m a
rand lo hi = do
    r <- get
    let (val, r') = randomR (lo, hi) r
    put r'
    return val
7
ответ дан 29 November 2019 в 06:42
поделиться

Часть определения «чистой» функции в Haskell состоит в том, что она референциально прозрачна , то есть взаимозаменяема с результатом ее вычисления. Это означает, что результат его оценки должен быть каждый раз одинаковым. Боюсь, желаемая функция невозможна.Чтобы сгенерировать случайные числа в Haskell, функция должна делать одно из двух:

Принимать и возвращать генератор псевдослучайных чисел, например:

randomPick :: RNG -> [a] -> (a, RNG)

Или использовать IO для доступа к случайности из «внешнего мира» ":

randomPick :: [a] -> IO a

Оба стиля предоставляются модулем System.Random . Кроме того, в первом случае передача PRNG может быть абстрагирована с помощью монады State или, возможно, монады специального назначения Random .

28
ответ дан 29 November 2019 в 06:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: