{ "cells": [ { "cell_type": "markdown", "id": "30657fb9", "metadata": {}, "source": [ "# Генератор случайных значений\n", "\n", "Создадим генератор чуть иначе, не как в прошлый раз. Внутреннее состояние генератора вынесем наружу. Теперь генератор случайных значений получает на вход состояние, возвращает случайное значение и следующее состояние:" ] }, { "cell_type": "code", "execution_count": 1, "id": "937f1749", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1,8,1,9,2,3,5,8,4,1]" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "State 144811957873548" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "newtype State = State Integer deriving Show -- как data, но эффективней\n", "newtype Random a = Random (State -> (a, State))\n", "\n", "nextState :: Integer -> Integer\n", "--nextState x0 = mod (134775813*x0 + 1) (2^32)\n", "nextState x0 = mod (25214903917*x0 + 11) (2^48)\n", "\n", "\n", "-- возвращает случайное значение и превращает старое состояние в новое\n", "generate :: Random a -> State -> (a, State)\n", "-- generate (Random f) state = f state\n", "generate (Random f) = f\n", "\n", "-- ползволяет сгенерировать N значений в списке из одного генератора. \n", "generateN :: Random a -> Int -> State -> ([a], State)\n", "generateN _ 0 state = ([], state)\n", "generateN random n state = (h : t, finalState) where\n", " (h, nextState) = generate random state\n", " (t, finalState) = generateN random (n - 1) nextState\n", "\n", "\n", "randomInRange :: Integer -> Integer -> Random Integer\n", "randomInRange min max = Random $ \\(State x0) -> (min + (x0 `div` (2^16) `mod` (max - min + 1)), State $ nextState x0)\n", "\n", "-- тестируем генерацию чисел\n", "random_1_10 = randomInRange 1 10\n", "\n", "state = State 13434\n", "let (x, nextState) = generateN random_1_10 10 state\n", "\n", "x\n", "nextState" ] }, { "cell_type": "markdown", "id": "45f68d95", "metadata": {}, "source": [ "Нужно сделать `Random` монадой. Сначала сделаем `Random` функтором:" ] }, { "cell_type": "code", "execution_count": 2, "id": "372d9a81", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "([Head,Tail,Head,Head,Head,Tail,Head,Tail,Head,Tail],State 147328094030846)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "([0,1,0,0,0,1,0,1,0,1],State 147328094030846)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "(Head,State 3101433181802)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "(0,State 3101433181802)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "instance Functor Random where\n", " -- g :: State -> a, f :: a -> b\n", " fmap f random = Random $ \\state -> (let\n", " (val, s2) = generate random state\n", " in (f val, s2)\n", " )\n", " \n", "random_0_1 = randomInRange 0 1\n", "data Coin = Head | Tail deriving Show\n", "genHeadTail = (\\x -> if x == 0 then Head else Tail) <$> random_0_1\n", "\n", "generateN genHeadTail 10 (State 1244)\n", "generateN random_0_1 10 (State 1244)\n", "\n", "generate genHeadTail (State 123)\n", "generate random_0_1 (State 123)\n" ] }, { "cell_type": "markdown", "id": "090234d1", "metadata": {}, "source": [ "Следующий шаг, сделаем `Random` аппликативным функтором.\n", "`<*> :: Random (a -> b) -> Random a -> Random b`" ] }, { "cell_type": "code", "execution_count": 3, "id": "d9b5d461", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
Use tuple-section
Found:
\\ state -> (x, state)
Why Not:
(x,)
" ], "text/plain": [ "Line 3: Use tuple-section\n", "Found:\n", "\\ state -> (x, state)\n", "Why not:\n", "(x,)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "instance Applicative Random where\n", " -- делает из обычного значения случайное, это генератор всегда одного значения\n", " pure x = Random (\\state -> (x, state))\n", " \n", " randomF <*> randomVal = Random (\\state -> let\n", " (f, state2) = generate randomF state\n", " (val, state3) = generate randomVal state2\n", " in (f val, state3)\n", " )\n" ] }, { "cell_type": "markdown", "id": "bc6045c4", "metadata": {}, "source": [ "Проверяем сумму двух случайных величин. Необходмо сделать `import`, чтобы заработал `liftA2`. " ] }, { "cell_type": "code", "execution_count": 4, "id": "48befde2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "([10,18,7,13,15,11,9,12,19,10,7,15,9,8,10,12,6,9,4,16,10,14,10,5,12,12,4,12,10,14,13,9,12,10,8,5,7,15,7,16,18,10,10,9,10,8,9,14,17,17,8,11,5,15,9,18,12,10,9,11,18,14,10,18,16,4,12,16,11,7,15,15,14,9,13,11,7,6,4,13,12,18,17,5,15,13,15,11,7,12,13,11,3,11,6,9,7,7,3,17],State 122086591259433)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import Control.Applicative\n", "random10plus10 = liftA2 (+) random_1_10 random_1_10\n", "-- или random10plus10 = (+) <$> random_1_10 <*> random_1_10\n", "generateN random10plus10 100 (State 1)" ] }, { "cell_type": "markdown", "id": "5c3d1131", "metadata": {}, "source": [ "Последний шаг, делаем `Random` монадой:" ] }, { "cell_type": "code", "execution_count": 5, "id": "149eedf7", "metadata": {}, "outputs": [], "source": [ "instance Monad Random where\n", " random >>= f = Random (\\state -> let\n", " (randomVal, state2) = generate random state\n", " (val, nextState) = generate (f randomVal) state2\n", " in (val, nextState))" ] }, { "cell_type": "markdown", "id": "29075e54", "metadata": {}, "source": [ "Создаем генератор, который складывает три случайных значения 0 или 1:" ] }, { "cell_type": "code", "execution_count": 6, "id": "2c0c2f6c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "([2,2,1,2,2,1,3,1,2,1,2,1,2,1,3,3,1,0,1,1,0,1,0,3,2,2,2,3,1,1,1,2,2,2,1,1,3,2,1,3,1,0,0,2,3,1,2,2,1,2,1,3,2,2,2,1,1,0,1,0,2,1,0,1,0,0,2,1,1,1,1,1,2,2,1,2,0,2,1,3,2,2,1,3,1,1,0,2,1,1,3,3,1,3,0,2,2,2,2,0],State 100669495570254)" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "r = do\n", " a <- randomInRange 0 1\n", " b <- randomInRange 0 1\n", " c <- randomInRange 0 1\n", " return $ a + b + c\n", " \n", "generateN r 100 (State 2)" ] } ], "metadata": { "kernelspec": { "display_name": "Haskell", "language": "haskell", "name": "haskell" }, "language_info": { "codemirror_mode": "ihaskell", "file_extension": ".hs", "mimetype": "text/x-haskell", "name": "haskell", "pygments_lexer": "Haskell", "version": "8.10.4" } }, "nbformat": 4, "nbformat_minor": 5 }