{ "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": [ "