user1602492
user1602492

Reputation:

Project Euler #4 using Haskell

I hope this works by just pasting and running it with "runghc euler4.hs 1000". Since I am having a hard time learning Haskell, can someone perhaps tell me how I could improve here? Especially all those "fromIntegral" are a mess.

module Main where
import System.Environment

main :: IO ()
main = do 
    args <- getArgs
    let 
        hBound = read (args !! 0)::Int
        squarePal = pal hBound
        lBound = floor $ fromIntegral squarePal / 
                   (fromIntegral hBound / fromIntegral squarePal)
        euler = maximum $ takeWhile (>squarePal) [ x | y <- [lBound..hBound], 
                                                       z <- [y..hBound],
                                                       let x = y * z,
                                                       let s = show x,
                                                       s == reverse s ]
    putStrLn $ show euler

pal :: Int -> Int
pal n
    | show pow == reverse (show pow) = n
    | otherwise = pal (n-1)
    where
        pow = n^2

Upvotes: 2

Views: 291

Answers (2)

Benjamin Kovach
Benjamin Kovach

Reputation: 3260

Okay, couple of things:

First, it might be better to pass in a lower bound and an upper bound for this question, it makes it a little bit more expandable.

If you're only going to use the first two (one in your previous case) arguments from the CL, we can handle this with pattern matching easily and avoid yucky statements like (args !! 0):

(arg0:arg1:_) <- getArgs

Let's convert these to Ints:

let [a, b] = map (\x -> read x :: Int) [arg0,arg1]

Now we can reference a and b, our upper and lower bounds. Next, let's make a function that runs through all of the numbers between an upper and lower bound and gets a list of their products:

products a b = [x*y | x <- [a..b], y <- [x..b]]

We do not have to run over each number twice, so we start x at our current y to get all of the different products.

from here, we'll want to make a method that filters out non-palindromes in some data set:

palindromes xs = filter palindrome xs
  where palindrome x = show x == reverse $ show x

finally, in our main function:

print . maximum . palindromes $ products a b

Here's the full code if you would like to review it:

import System.Environment
main = do
  (arg0:arg1:_) <- getArgs
  let [a, b] = map (\x -> read x :: Int) [arg0,arg1]
  print . maximum . palindromes $ products a b

products a b = [x*y | x <- [a..b], y <- [x..b]]

palindromes = filter palindrome
  where palindrome x = (show x) == (reverse $ show x)

Upvotes: 0

lbolla
lbolla

Reputation: 5411

If what you want is integer division, you should use div instead of converting back and forth to Integral in order to use ordinary /.

module Main where                                                              
import System.Environment                                                      

main :: IO ()                                                                  
main = do                                                                      
    (arg:_) <- getArgs                                                         
    let                                                                        
        hBound = read arg :: Int                                               
        squarePal = pal hBound                                                 
        lBound = squarePal * squarePal `div` hBound                            
        euler = maximum $ takeWhile (>squarePal) [ x | y <- [lBound..hBound],
                                                       z <- [y..hBound],       
                                                       let x = y * z,          
                                                       let s = show x,         
                                                       s == reverse s ]        
    print euler                                                                

pal :: Int -> Int                                                              
pal n                                                                          
    | show pow == reverse (show pow) = n                                       
    | otherwise = pal (n - 1)                                                  
    where                                                                      
        pow = n * n                                                            

(I've re-written the lbound expression, that used two /, and fixed some styling issues highlighted by hlint.)

Upvotes: 1

Related Questions