Ruben Rubensson
Ruben Rubensson

Reputation: 31

What's a valid replacement for "None" as an empty return value in this case

I want to return None (Or Haskell's equivalent to None, rather) to this list of valid factors and whenever I encounter a number that isn't valid (a number that doesn't return a value of 0 when I run it in the modulus function along with x), I want to return None so that the list only contains the factors. There might be some errors in the code, I am new to Haskell, so you'll have to excuse sloppy code and such.

I've tried using return maybe x, since I heard that it would work, but I had no luck with it (might've been using it incorrectly, though). I also thought about using some kind of standard value and using a seoarate function to filter the values out, but I reckoned that there must be a better way.

import Data.List
import System.IO

checkPerfect x
    | x == sum factor x = return x
    | otherwise = return None

factor x
    | mod x [1..x-1] == 0 = return x
    | otherwise = return None

main = do
    putStrLn "Upper limit?"
    limit <- readLn
    let uncheckedNumbers = [1..limit]
    let perfectNumbersRaw = map checkPerfect uncheckedNumbers
    putStrLn ("Perfect numbers: " ++ perfectNumbersRaw)

Upvotes: 2

Views: 248

Answers (2)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477190

Usually a Maybe a type is used to return a computation that can fail, or an Either String a where the Left constructor returns an error message.

Note that Haskell has no return statement. return is a function that is used for monads. Strictly speaking, you can use return here to wrap the result in a Just constructor, but it is probably more readable to do that explicitly.

That being said, your program has a lot of problems, both syntactically and semantically:

  1. "In number theory, a perfect number is a positive integer that is equal to the sum of its positive divisors, excluding the number itself." [wiki], not factors.
  2. x == sum factor x will not calculate the sum of the factors/divisors, since factor will return a single number (probably wrapped in a Maybe), yes, you can calculate the sum of a Num a => Maybe a type, but that is the sum of the only item it wraps, or 0 in case of a Nothing;
  3. as said, you probably should not use return here in the first place, Haskell has no return statement;
  4. you can not append a string with a list of numbers, you can however use show :: Show a => a -> String to convert it to a string;
  5. by using map checkPerfect you will generate a list that contains for each item a Just x or a Nothing, you probably want to use filter instead.

I think it makes more sense here to return a Bool instead, and then filter the list:

checkPerfect :: Integral i => i -> Bool
checkPerfect x = x == sum (filter ((==) 0 . mod x) [1 .. x-1])

or as @melpomene says with list comprehension:

checkPerfect :: Integral i => i -> Bool
checkPerfect x = x == sum [ k | k <- [1 .. x-1], mod x k == 0 ]

and then print the list of items with:

main = do
    putStrLn "Upper limit?"
    limit <- readLn :: IO Int
    putStrLn ("Perfect numbers: " ++ show (filter checkPerfect [1 .. limit]))

If we take as limit 10'000, we get:

Prelude> main
Upper limit?
10000
Perfect numbers: [6,28,496,8128]

Upvotes: 11

Yann Vernier
Yann Vernier

Reputation: 15887

The Maybe type is the primary optional type in Haskell. For instance, you could use Just x and Nothing, or using its Monad, return x and fail "not perfect". Note that return is a function of monads, moving values from pure (which is frequently the Applicative name for the same function) to monadic, and not needed when you don't need to wrap a value.

Upvotes: 4

Related Questions