Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do while loop in Haskell

I have a function:

isItSimple :: Int -> Bool

it gets Int and return Bool.

I need to find first number in [x | x <- [n..], isItSimple x].

Here is my solution:

findIt :: Int -> Int
findIt num
       | isItSimple num = num
       | otherwise = findIt (num + 1)

Is there any better solution in Haskell?

like image 291
ceth Avatar asked Nov 27 '22 23:11

ceth


2 Answers

I need to find first number in [x | x <- [n..], isItSimple x].

How about just like you said.

findIt n = head [ x | x <- [n..], isItSimple x ]
like image 124
luqui Avatar answered Jan 13 '23 02:01

luqui


While the other answers work, they're arguably not the most idiomatic way to solve this problem in Haskell. You don't really need any extra imports: a couple of functions from the Prelude will do the trick.

I'd start by creating a list of all of the simple numbers greater than or equal to n. The function filter :: (a -> Bool) -> [a] -> [a] makes this easy:

filter isItSimple [n..]

Like [n..] this is an infinite list, but this isn't a problem since Haskell is lazy and won't evaluate anything until it's needed.

To get what you want you can just take the head of this infinite list:

findIt :: Int -> Int
findIt n = head $ filter isItSimple [n..]

Some people don't like head since it's a partial function and will raise an exception when it's given an empty list. I personally wouldn't worry about that here, since we know it will never be called on an empty list. It makes me much less uncomfortable than fromJust, which is also a partial function (it raises an exception when given Nothing) and in my opinion is always a bad idea.

(And speaking of personal taste, I'd write this as follows:

findIt = head . filter isItSimple . enumFrom

This is an example of pointfree style, which can get convoluted but in this case is very elegant, in my opinion.)

like image 25
Travis Brown Avatar answered Jan 13 '23 04:01

Travis Brown