Search code examples
haskellsquare

Square of even numbers in Haskell


I am trying to write a basic function in Haskell as shown below. My aim is provide the code to square only even numbers while odd numbers will stay same. Would you please help me regarding this issue.

square:: Int -> Int
square x = [ x*x | x <- [1..10], mod x 2 == 0 ]

regards


Solution

  • One quite straightforward answer to your question is, you can inline a if statment directly into your list comprehension like so:

    [ if even x then x * x else x | x <- [1..10] ]
    

    This is possible since if is an expression in Haskell, meaning it evaluates to a value, so things like this are valid:

    let _ = if 1 + 1 == 2 then "foo" else "bar"
    

    It can also be good to look at this problem in another direction. List comprehensions can be quite nice, but sticking an if within it can get pretty messy. Willem's solution of factoring out the method is great, so let's look at other ways we can leverage it with your code:

    -- This is the function we're trying to implement
    evenSquares :: [Int] -> [Int]
    
    -- We could start by noting that `if` expression has a nice name,
    -- which can be factored out to make things look cleaner
    -- Same implementation as Willem's
    evenSquares xs = [ squareIfEven x | x <- xs ] where
      squareIfEven x = if even x then x * x else x
    
    -- List comprehensions are nice, but there's also another name for what we're doing,
    -- which is mapping over a collection of values and applying a method
    evenSquares xs = map squareIfEven xs where 
      squareIfEven x = if even x then x * x else x
    
    -- Note how the `xs` is an argument to `evenSquares` and also the last argument to `map`
    -- We can actually get rid of `xs` entirely via this rule:
    -- https://wiki.haskell.org/Eta_conversion
    evenSquares = map squareIfeven where
      squareIfEven x = if even x then x * x else x
    
    -- This one's a bit of a stretch, but conceptually quite useful
    -- The idea of 'apply a method if a condition is true' can be expressed as a method
    -- which takes a predicate method, a transformation method, and a value
    -- We can leverage this ourselves to make `squareIfEven` more generic too
    evenSquares = map (if' even square id) where
      square x = x * x
      if' pred fst snd x = if pred x then fst x else snd x
    
    -- There's a bunch more solutions we can try, including things like `do` notation
    -- This is just an idea of how you could look at your problem
    -- Pick one which makes your solution clear and concise!