Finding Keith Numbers with Haskell

I'm on day 2 of learning Haskell, and decided to write a program to find Keith Numbers as my first project. So far so good, I have some code that does the job (see below). First I would just like to ask others to look it over and let me know if I am doing anything particularly wrong or not advised here. Also, I am using the "isKeithHelper" function because I didn't know how to make use of the filter function directly with isKeith, because isKeith takes two parameters. I'm pretty sure there is a better way to handle that, any tips? Lastly, I'd like to make this as efficient as possible. At the moment I am adding [s] to the end of the list in the isKeith function, which I know is O(n) instead of O(1). I don't think there is a way to avoid either that or having to use drop which would have the same downside. Is this a case where a Sequence or Vector might be more useful? How would I convert this to use a Sequence instead? import Data.Time.Clock.POSIX import Data.Digits isKeith :: Integer -> [Integer] -> Bool isKeith n l | s == n = True | s > n = False | otherwise = isKeith n x (l ++ [s]) where s = sum l isKeithHelper :: Integer -> Bool isKeithHelper n = isKeith n (digits 10 n) main :: IO () main = do start <- getPOSIXTime print (filter isKeithHelper [1000..9999]) end <- getPOSIXTime print (end - start)

Since summing is commutative (sum [a,b] = sum [b,a]), it doesn't matter what order they appear in. You can start out by reversing the digits and then by taking from and adding to the beginning of the list instead of the end. Also, isKeith needs to know the length of the decimal representation of n. Since you are already computing that representation in isKeithHelper, it might be best to compute this there as well and pass it into isKeith. (Also please consider the criterion library for benchmarking.)
import Data.Digits
isKeith :: Int -> Bool isKeith n = let ds = digitsRev 10 n in isKeith' n (length ds) ds
isKeith' :: Int -> Int -> [Int] -> Bool isKeith' n len ds | n == s = True | s > n = False | otherwise = isKeith' n len (take len (s : ds)) where s = sum ds
main :: IO () main = print (isKeith 197)
True

Thanks, is the notation with the single quote (isKeith') a convention for
helper functions or does it actually change something about the program?
I did try this approach as well, reversing the digits and adding elements
to the head, however having to use take and letting the list build up
larger seems to result in slightly worse performance overall.
On Mon, Nov 10, 2014 at 8:50 PM, Rein Henrichs
Since summing is commutative (sum [a,b] = sum [b,a]), it doesn't matter what order they appear in. You can start out by reversing the digits and then by taking from and adding to the beginning of the list instead of the end. Also, isKeith needs to know the length of the decimal representation of n. Since you are already computing that representation in isKeithHelper, it might be best to compute this there as well and pass it into isKeith.
(Also please consider the criterion library for benchmarking.)
import Data.Digits
isKeith :: Int -> Bool isKeith n = let ds = digitsRev 10 n in isKeith' n (length ds) ds
isKeith' :: Int -> Int -> [Int] -> Bool isKeith' n len ds | n == s = True | s > n = False | otherwise = isKeith' n len (take len (s : ds)) where s = sum ds
main :: IO () main = print (isKeith 197)
True
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Tue, Nov 11, 2014 at 8:26 PM, Jack Mott
Thanks, is the notation with the single quote (isKeith') a convention for helper functions or does it actually change something about the program?
An unspoken coding convention. Function foo' would be read "foo-prime". E.g.of usage: haskell-prime is the next standard of haskell, which became moot because you need good vibes for diverse peoples to collaborate on such an undertaking, including supporting it by writing more than one implementation. Strictly syntax, the compiler doesn't treat it differently from any other name label. So yes, you could have foo-double-prime and so forth. -- Kim-Ee

On Tue, Nov 11, 2014 at 8:26 PM, Jack Mott
wrote: Thanks, is the notation with the single quote (isKeith') a convention for helper functions or does it actually change something about the program?
An unspoken coding convention.
Function foo' would be read "foo-prime". E.g.of usage: haskell-prime is the next standard of haskell, which became moot because you need good vibes for diverse peoples to collaborate on such an undertaking, including supporting it by writing more than one implementation.
Strictly syntax, the compiler doesn't treat it differently from any other name label.
So yes, you could have foo-double-prime and so forth. It's inherited from maths (like everything else). Very commonly used for a changed/new version of something. Comes up a lot in games
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 On 11/11/14 16:17, Kim-Ee Yeoh wrote: programming. One banal example: update :: World -> World update (World p p2 b e) = let p' = update p p2' = update p2 b' = update b e' = update e in World p' p2' b' e' where update = draw . move . react - -- Alexander alexander@plaimi.net https://secure.plaimi.net/~alexander -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/ iF4EAREIAAYFAlRjIzcACgkQRtClrXBQc7WPHwEAuIDb/vALYJ6Duz2ZDdB/tqHs l35idQYgOkngDrVe4pwA/0PcF4IUv8MwBAOI3kE8OiBDFTPhsS2SlRtmgihqXwty =XyN/ -----END PGP SIGNATURE-----

On Tue, Nov 11, 2014 at 5:26 AM, Jack Mott
I did try this approach as well, reversing the digits and adding elements to the head, however having to use take and letting the list build up larger seems to result in slightly worse performance overall.
The list doesn't build up. The specification for Keith Numbers requires that we only sum the previous n numbers, where n is the length of the decimal encoding of the given number, so we always truncate using take before the recursive call.
participants (4)
-
Alexander Berntsen
-
Jack Mott
-
Kim-Ee Yeoh
-
Rein Henrichs