Prime factors and perfect square I want to convert an integer to a perfect square by multiplying it by some number. That number is the product of all the prime factors of the number which not appear an even number of times. Example 12 = 2 x 2 x 3; 2 appears twice (even number of times) but 3 just once (odd number of times), so the number I need to multiply 12 by to get a perfect square is 3. And in fact 12 x 3 = 36 = 6 * 6.

I converted my code to Haskell and would like to know what suggestions you have.

import Data.List (group)

toPerfectSquare :: Int -&gt; Int
toPerfectSquare n = product . map (\(x:_) -&gt; x) . filter (not . even . length) . group $ primefactors n

primefactors :: Int -&gt; [Int]
primefactors n = prmfctrs' n 2 [3,5..]
  where
    prmfctrs' m d ds | m &lt; 2     = [1]
                     | m &lt; d^2   = [m]
                     | r == 0    = d : prmfctrs' q d ds
                     | otherwise = prmfctrs' m (head ds) (tail ds)
      where (q, r) = quotRem m d


Sorry about the naming, I'm bad at giving names.

One particular doubt I have is in the use of $ in toPerfectSquare, that I first used . but it didn't work and I needed to use parenthesis. Why? And is it usual to have that many compositions in one line?
We can replace some custom functions or constructs by standard library ones:


\(x:_) -&gt; x is called head
not . even is called odd


Next, 1 is not a prime, and 1 does not have a prime factorization. Since product [] yields 1, we can use [] instead in prmfctrs'.

The worker prmfctrs' is a mouthful. Workers are usually called the same as their context (but with an apostrophe, so primefactors') or short names like go.

And last but not least, we can use @ bindings to pattern match on the head, tail and the whole list at once.

If we apply those suggestions, we get

import Data.List (group)

toPerfectSquare :: Int -&gt; Int
toPerfectSquare n = product . map head . filter (odd . length) . group $ primefactors n

primefactors :: Int -&gt; [Int]
primefactors n = go n 2 [3,5..]
  where
    go m d ds@(p:ps) | m &lt; 2     = []
                     | m &lt; d^2   = [m]
                     | r == 0    = d : go q d ds
                     | otherwise = go m p ps
      where (q, r) = quotRem m d


In theory, we can even get rid of a parameter in go, namely the d, so that we always just look at the list of the divisors:

import Data.List (group)

toPerfectSquare :: Int -&gt; Int
toPerfectSquare n = product . map head . filter (odd . length) . group $ primefactors n

primefactors :: Int -&gt; [Int]
primefactors n = go n $ 2 : [3,5..]
  where
    go m dss@(d:ds) | m &lt; 2     = []
                    | m &lt; d^2   = [m]
                    | r == 0    = d : go q dss
                    | otherwise = go m ds
      where (q, r) = m `quotRem` d


We could also introduce another function \$f\$, so that for any \$a,b \in \mathbb N\$ we get a pair \$(n,y) \in \mathbb N^2\$ such that

$$
a^n y = b
$$
If we had that function, we could write use it to check easily whether the power of a given factor is even or odd. However, that function and its use in toPerfectSquare are left as an exercise.