3
votes

I'm new to Haskell, started learning a couple of days ago and I have a question on a function I'm trying to make.

I want to make a function that verifies if x is a factor of n (ex: 375 has these factors: 1, 3, 5, 15, 25, 75, 125 and 375), then removes the 1 and then the number itself and finally verifies if the number of odd numbers in that list is equal to the number of even numbers!

I thought of making a functions like so to calculate the first part:

factor n = [x | x <- [1..n], n `mod`x == 0]

But if I put this on the prompt it will say Not in scope 'n'. The idea was to input a number like 375 so it would calculate the list. What I'm I doing wrong? I've seen functions being put in the prompt like this, in books.

Then to take the elements I spoke of I was thinking of doing tail and then init to the list. You think it's a good idea?

And finally I thought of making an if statement to verify the last part. For example, in Java, we'd make something like:

(x % 2 == 0)? even++ : odd++; // (I'm a beginner to Java as well)

and then if even = odd then it would say that all conditions were verified (we had a quantity of even numbers equal to the odd numbers)

But in Haskell, as variables are immutable, how would I do the something++ thing?

Thanks for any help you can give :)

5
You have to use recursion. learnyouahaskell.com/recursionelimirks
@elimirks Thank you :DBVCGAAV

5 Answers

5
votes

This small function does everything that you are trying to achieve:

f n = length evenFactors == length oddFactors
  where evenFactors = [x | x <- [2, 4..(n-1)], n `mod` x == 0]
        oddFactors  = [x | x <- [3, 5..(n-1)], n `mod` x == 0]
3
votes

If the "command line" is ghci, then you need to

let factor n = [x | x <- [2..(n-1)], n `mod` x == 0]

In this particular case you don't need to range [1..n] only to drop 1 and n - range from 2 to (n-1) instead.

The you can simply use partition to split the list of divisors using a boolean predicate:

import Data.List
partition odd $ factor 10

In order to learn how to write a function like partition, study recursion.

For example:

partition p = foldr f ([],[]) where
  f x ~(ys,ns) | p x = (x:ys,ns)
  f x ~(ys,ns) = (ys, x:ns)

(Here we need to pattern-match the tuples lazily using "~", to ensure the pattern is not evaluated before the tuple on the right is constructed).

Simple counting can be achieved even simpler:

let y = factor 375
(length $ filter odd y) == (length y - (length $ filter odd y))
2
votes

Create a file source.hs, then from ghci command line call :l source to load the functions defined in source.hs.

To solve your problem this may be a solution following your steps:

-- computers the factors of n, gets the tail (strips 1)
-- the filter functions removes n from the list
factor n = filter (/= n) (tail [x | x <- [1..n], n `mod` x == 0])

-- checks if the number of odd and even factors is equal
oe n = let factors = factor n in 
           length (filter odd factors) == length (filter even factors)

Calling oe 10 returns True, oe 15 returns False

1
votes
(x % 2 == 0)? even++ : odd++;

We have at Data.List a partition :: (a -> Bool) -> [a] -> ([a], [a]) function

So we can divide odds like

> let (odds,evens) = partition odd [1..]

> take 10 odds
 [1,3,5,7,9,11,13,15,17,19]
> take 10 evens
 [2,4,6,8,10,12,14,16,18,20]
0
votes

Here is a minimal fix for your factor attempt using comprehensions:

factor nn = [x | n <- [1..nn], x <- [1..n], n `mod`x == 0]