|  | @@ -1,39 +1,47 @@
 | 
	
		
			
				|  |  |  module Main where
 | 
	
		
			
				|  |  | -import Numeric (showHex)
 | 
	
		
			
				|  |  | +import Numeric (showIntAtBase)
 | 
	
		
			
				|  |  |  import Data.List (isInfixOf, genericIndex)
 | 
	
		
			
				|  |  |  import Data.List.Split(splitOn)
 | 
	
		
			
				|  |  |  import Text.Read (readMaybe)
 | 
	
		
			
				|  |  |  import System.IO (hFlush, stdout)
 | 
	
		
			
				|  |  | +import System.Environment (getArgs)
 | 
	
		
			
				|  |  | +import System.Exit (exitWith, ExitCode(ExitSuccess))
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -hexPi :: Integer -> Char
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +-- Get the hex representation of Pi at place n.
 | 
	
		
			
				|  |  | +hexPi :: Integer -> Integer
 | 
	
		
			
				|  |  |  hexPi n =
 | 
	
		
			
				|  |  |    let
 | 
	
		
			
				|  |  |      summation = (4 * sumPi n 1) - (2 * sumPi n 4) - (sumPi n 5) - (sumPi n 6)
 | 
	
		
			
				|  |  | -    skimmedSum = summation - (fromIntegral (floor summation :: Integer))
 | 
	
		
			
				|  |  | +    skimmedSum = summation - (fromIntegral (floor summation :: Integer)) -- Take only the decimal portion
 | 
	
		
			
				|  |  |    in
 | 
	
		
			
				|  |  | -    showHex (floor (16 * skimmedSum) :: Integer) "" !! 0
 | 
	
		
			
				|  |  | +    floor (16 * skimmedSum) :: Integer
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +-- Calculate the summation.
 | 
	
		
			
				|  |  | +-- 5000 is used in place of Infinity. This value drops off quickly, so no need to go too far.
 | 
	
		
			
				|  |  |  sumPi :: Integer -> Integer -> Double
 | 
	
		
			
				|  |  |  sumPi n x =
 | 
	
		
			
				|  |  |    let
 | 
	
		
			
				|  |  |      summation1 = [(fromIntegral ((16^(n-k) `mod` ((8*k)+x)))) / (fromIntegral ((8*k)+x)) | k <- [0..n]]
 | 
	
		
			
				|  |  | -    -- 5000 is used in place of Infinity. This value drops off quickly, so no need to go too far.
 | 
	
		
			
				|  |  |      summation2 = [16^^(n-k) / (fromIntegral ((8*k)+x)) | k <- [(n+1)..5000]]
 | 
	
		
			
				|  |  |    in
 | 
	
		
			
				|  |  |      sum $ summation1 ++ summation2
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -rangePi :: Maybe Integer -> Maybe Integer -> IO ()
 | 
	
		
			
				|  |  | -rangePi num1 num2 = do
 | 
	
		
			
				|  |  | -  case (num1, num2) of
 | 
	
		
			
				|  |  | -    (Just one, Just two) ->
 | 
	
		
			
				|  |  | -      if one >= two then
 | 
	
		
			
				|  |  | -        putStrLn "Please give a proper range."
 | 
	
		
			
				|  |  | -      else
 | 
	
		
			
				|  |  | -        putStrLn $ foldr (:) [] (drop (fromIntegral one) . take (fromIntegral two) $ hexDigits)
 | 
	
		
			
				|  |  | -    (_,_) -> putStrLn "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -prompt :: IO ()
 | 
	
		
			
				|  |  | -prompt = do
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +-- Get a range of digits.
 | 
	
		
			
				|  |  | +rangePi :: (Integer -> String) -> Maybe Integer -> Maybe Integer -> String
 | 
	
		
			
				|  |  | +rangePi printFun (Just low) (Just high) =
 | 
	
		
			
				|  |  | +  if low >= high then
 | 
	
		
			
				|  |  | +    "Error: Please give a proper range."
 | 
	
		
			
				|  |  | +  else
 | 
	
		
			
				|  |  | +    foldr (++) [] (map printFun (drop (fromIntegral low) . take (fromIntegral high) $ hexDigits))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +rangePi _ _ _  = printErr
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +prompt :: (Integer -> String) -> IO ()
 | 
	
		
			
				|  |  | +prompt printFun = do
 | 
	
		
			
				|  |  |    putStr ":: "
 | 
	
		
			
				|  |  |    hFlush stdout
 | 
	
		
			
				|  |  |    response <- getLine
 | 
	
	
		
			
				|  | @@ -41,19 +49,50 @@ prompt = do
 | 
	
		
			
				|  |  |    if (isInfixOf ".." response) then
 | 
	
		
			
				|  |  |      let
 | 
	
		
			
				|  |  |        range = splitOn ".." response
 | 
	
		
			
				|  |  | +      low = readMaybe $ range !! 0 :: Maybe Integer
 | 
	
		
			
				|  |  | +      high = readMaybe $ range !! 1 :: Maybe Integer
 | 
	
		
			
				|  |  |      in
 | 
	
		
			
				|  |  | -      rangePi (readMaybe $ range !! 0 :: Maybe Integer) (readMaybe $ range !! 1 :: Maybe Integer)
 | 
	
		
			
				|  |  | +      putStrLn $ rangePi printFun low high
 | 
	
		
			
				|  |  |      else do
 | 
	
		
			
				|  |  |        case (readMaybe response :: Maybe Integer) of
 | 
	
		
			
				|  |  | -        Nothing -> putStrLn "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
 | 
	
		
			
				|  |  | -        Just x -> putStrLn $ hexDigits `genericIndex` x :[]
 | 
	
		
			
				|  |  | -  prompt
 | 
	
		
			
				|  |  | +        Nothing -> putStrLn printErr
 | 
	
		
			
				|  |  | +        Just x -> putStrLn $ printFun $ hexDigits `genericIndex` x
 | 
	
		
			
				|  |  | +  prompt printFun
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | --- Establish the list of answers
 | 
	
		
			
				|  |  | -hexDigits :: [Char]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +-- The list of answers.
 | 
	
		
			
				|  |  | +hexDigits :: [Integer]
 | 
	
		
			
				|  |  |  hexDigits = [hexPi x | x <- [0..]]
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +-- Complain about argument type.
 | 
	
		
			
				|  |  | +printErr :: String
 | 
	
		
			
				|  |  | +printErr = "Error: Please give an Integer (ex: 3) or a range (ex: 3..5)."
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  main :: IO ()
 | 
	
		
			
				|  |  |  main = do
 | 
	
		
			
				|  |  | -  putStrLn "Enter a digit or range (Ctrl-C to exit)"
 | 
	
		
			
				|  |  | -  prompt 
 | 
	
		
			
				|  |  | +  -- Get formatter function (hex, binary, or decimal)
 | 
	
		
			
				|  |  | +  args <- getArgs
 | 
	
		
			
				|  |  | +  let
 | 
	
		
			
				|  |  | +    printFunIO =
 | 
	
		
			
				|  |  | +      case args of
 | 
	
		
			
				|  |  | +          ["-b"] -> do
 | 
	
		
			
				|  |  | +            putStrLn "Outputting in binary."
 | 
	
		
			
				|  |  | +            return (\n -> showIntAtBase 2 (\x -> show x !! 0) n "")
 | 
	
		
			
				|  |  | +          ["-d"] -> do
 | 
	
		
			
				|  |  | +            putStrLn "Outputting in decimal."
 | 
	
		
			
				|  |  | +            return (\n -> show n ++ " ")
 | 
	
		
			
				|  |  | +          ["-h"] -> do
 | 
	
		
			
				|  |  | +            putStrLn "Generate hexadecimal Pi digits. Output in hexidemical by default.\n\
 | 
	
		
			
				|  |  | +                     \\t-b\tOutput in binary.\n\
 | 
	
		
			
				|  |  | +                     \\t-d\tOutput in decimal.\n\
 | 
	
		
			
				|  |  | +                     \\t-h\tShow this help message."
 | 
	
		
			
				|  |  | +            exitWith ExitSuccess
 | 
	
		
			
				|  |  | +          _ -> do
 | 
	
		
			
				|  |  | +            putStrLn "Outputting in hex."
 | 
	
		
			
				|  |  | +            return (\n -> showIntAtBase 16 (\x -> show x !! 0) n "")
 | 
	
		
			
				|  |  | +    in do
 | 
	
		
			
				|  |  | +      printFun <- printFunIO
 | 
	
		
			
				|  |  | +      putStrLn "Enter a digit or range (Ctrl-C to exit)."
 | 
	
		
			
				|  |  | +      prompt printFun
 |