packages feed

Hs2lib-0.4.8: Tests/Src/Test_Getallen.hs

module Tests.Src.Test_Getallen where

import Data.List
import Data.Maybe
import Control.Monad
import Control.Arrow



unfoldl :: (t -> Maybe (a, t)) -> t -> [a]
unfoldl f x = case f x of 
                Nothing -> []
                Just (u,v) -> unfoldl f v ++ [u] -- we miss you wli

-- @@ Export
-- | This is a reverse of the original divMod function, it's useful with unfoldl
modDiv :: Integer -> Integer -> (Integer, Integer)
modDiv = \a -> (snd &&& fst).(divMod a)

-- @@ Export
-- | calculate the decimal representation of a number from it's components
--   .
--   e.g. fromDec [1,2,3] = 123
--   .
--   The inverse of toDec
fromDec :: [Integer] -- ^ The list of decimal numbers to combine
        -> Integer -- ^ The combined representation of the input
fromDec = foldl' ((+).(*10)) 0

-- @@ Export
-- | calculate from a decimal number it's components
--   .
--   e.g. toDec 123 = [1,2,3]
--   .
--   The inverse of fromDec
toDec :: Integer -- ^ The decimal number to break into it's sub components
      -> [Integer] -- ^ The result from decomposing the input
toDec 0 = [0]
-- toDec x = (reverse.(unfoldr (\a-> let b = a `mod` 10 
                                  -- in if a == 0 then Nothing 
                                     -- else Just (b,(a-b) `div` 10)))) x
toDec x = unfoldl (\x -> guard (x /= 0) >> return (x `modDiv` 10)) x
            
-- @@ Export
-- | Calculate from a list of binary digits the corresponding decimal number
--   . 
--   e.g. fromBin [1,0,1] = 5
--   .
--   The inverse of toBin
fromBin :: [Integer] -- ^ The list of bits to convert
        -> Integer -- ^ The resulting nnumber converted from binary
fromBin x = fromBin' (length x - 1) x   
 where fromBin' _ []     = 0
       fromBin' c (x:xs) = x*2^c + fromBin' (c-1) xs
       
-- @@ Export
-- | Calculate from a decimal number the corresponding binary digit components
--   . 
--   e.g. toBin 5 = [1,0,1]
--   .
--   The inverse of fromBin
toBin :: Integer -- ^ The input number to convert to binary
      -> [Integer] -- ^ The list consisting of the bits of the computation
toBin 0 = [0]
toBin x = (unfoldl (\a -> guard (a /= 0) >> return (a `modDiv` 2))) x
-- toBin = reverse.(unfoldr (\a -> if a == 0 then Nothing 
                                -- else let b = a `mod` 2 
                                     -- in Just (b,a `div` 2)))

-- @@ Export = fromBaseMaybe
-- | Calculate given the base and the input string with the number to encode 
--   the corresponding encoding. 
--   .
--   e.g. fromBase2 2 "101" = Just 5
--   .
--   This can ofcourse fail, to encode this there's a Maybe in the return type.
--   .
--   e.g. fromBase2 1 "101" = Nothing
fromBase2 :: Int -- ^ The numerical base
          -> String -- ^ The input string to convert
          -> Maybe Int -- ^ The result of the conversion, which may have failed
fromBase2 b i = fromBase' (take b $ ['0'..'9']++['a'..'z']) (length i-1) i
 where fromBase' _ _ []     = Just 0
       fromBase' a i (x:xs) = let val  = (elemIndex x a)
                                  rec_ = fromBase' a (i-1) xs
                              in liftM2 (+) (fmap (*b^i) val) rec_
            
-- @@ Export    
-- | A version of fromBase2 (fromBaseMaybe) where failure is not encoded.
--   If it fails it'll produce a crash.
--   .
--   see fromBase2 (fromBaseMaybe)
--   .
--   The inverse of toBase
fromBase :: Int -- ^ The numerical base to use
         -> String -- ^ The number to convert
         -> Int -- ^ The converted number to the destination base
fromBase a b= fromJust (fromBase2 a b)
            
-- @@ Export
-- | A encode a number using the given base. The result is encoded into a string.
--   .
--   e.g. toBase 2 5 = "101"
--   .
--   . The inverse of fromBase
toBase :: Int -- ^ The numerical base to use
       -> Int -- ^ The number to convert
       -> String -- ^ The converted number to the destination base
toBase b = toBase' (take b $ ['0'..'9']++['a'..'z'])
 where toBase' d i = case i of
                        0 -> "0"
                        _ -> (unfoldl (\a -> guard (a /= 0) >> return ( d !! (a `mod` b),a `div` b))) i
            
-- @@ Export
-- | Calculate the result of converting the list of strings using the given base into a tuple
--   .
--   which contains the (input, representation)
--   .
--   this is done using fromBase2. Encodings that fail will simple not be included in the resulting list.
--   .
--   numbers 2 ["101010","10101"] = [("101010",42),("10101",21)]
--   .
--   numbers 2 ["12345" ,"10101"] = [("10101",21)]
numbers :: Int -- ^ The numerical base
        -> [String] -- ^ The list of number to convert to the given base.
        -> [(String,Int)] -- ^ The result of the conversion, the first part of the tuple is the original input and the second part the converted number
numbers b i =  mapMaybe (uncurry (fmap . (,))) $ zip i (fmap (fromBase2 b) i)

grayCode :: Int -> (String -> Int, Int -> String)
grayCode base = (fromBase base,toBase base)

lookAndSay :: Int -> [String]
lookAndSay x = look (show x)
 where look :: String -> [String]
       look y = let lst  = group y
                    res  = concatMap (\x->show (length x) ++ [head x]) lst
                in y:look res
                
keithGetallen :: [Integer]
keithGetallen = [x | x <- [10..], genNumberSec x]
            
-- @@ Export
-- | Checks to see if a number is a valid keith number.
genNumberSec :: Integer -- ^ The number to check whether it's a keith number or not
             -> Bool -- ^ The answer to whether the number given as input is a keith number
genNumberSec xo = gen no
 where gen x = let res = sum (drop (length x-n) x)
               in  case compare res xo of
                      GT -> False
                      EQ -> True
                      LT -> gen (x++[res])
       no = toDec xo
       n = length no