Last active
November 24, 2016 18:01
-
-
Save jpablo/b01c56c74c84395b886f63baf01a905f to your computer and use it in GitHub Desktop.
IO Monad, Random numbers in Haskell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- required: stack install random | |
import System.Random | |
-------- Fermat test ----------------- | |
expmod base e m | |
| e == 0 = 1 | |
| even e = mod (expmod base (e `div` 2) m ^ 2) m | |
| otherwise = mod (base * expmod base (e - 1) m) m | |
-- just to mimic the book | |
-- random between 1 and n inclusive | |
random' :: Int -> IO Int | |
random' n = randomRIO (1, n :: Int) | |
-- Scala: random': Int => IO[Int] | |
-- since random' is a monadic function (the result is wrappend inside a Monad) | |
-- we need to use a do notation (similar to Scala's for comprehension) | |
fermatTest :: Int -> IO Bool | |
fermatTest n = do | |
r <- random' $ n-1 | |
return $ tryIt r | |
where | |
tryIt a = expmod a n n == a | |
-- Scala: | |
-- | |
-- def fermatTest(n: Int): IO[Bool] = { | |
-- def tryIt(a: Int) = expmod(a,n,n) == a | |
-- for (r <- random'(n-1)) yield tryIt(r) | |
-- } | |
fastPrime n 0 = return True | |
fastPrime n times = do | |
t <- fermatTest n | |
if t then fastPrime n (times-1) else return False | |
--------- IO Monad ------------ | |
-- rIO = randomRIO(1,10 :: Int) | |
-- fmap (+1) $ rIO == (+1) <$> rIO | |
-- alternative versions without do notation | |
-- fmap f b == f <$> b | |
-- using where | |
fermatTest' n = tryIt <$> random' (n-1) | |
where | |
tryIt a = expmod a n n == a | |
-- using let / in | |
fermatTest'' n = | |
let tryIt a = expmod a n n == a | |
in tryIt <$> random' (n-1) | |
fermatTest''' n = (\a -> expmod a n n == a) <$> random' (n-1) | |
-- Scala: | |
-- def fermatTest(n: Int) = random(n-1).map(a => expmod(a,n,n) == a) | |
fastPrime' n 0 = return True | |
fastPrime' n times = fermatTest n >>= (\t -> if t then fastPrime n (times-1) else return False) | |
-- Scala: | |
-- def fastPrime(n: Int, times: Int): IO[Bool] = fermatTest(n).flatMap(t => if (t) fastPrime(n, times-1) else IO(false)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment