CYC
CYC

Reputation: 629

While in a loop in Haskell

How to code the following pseudo-code in Haskell?

x=0
for (i from 0 to 100):
    j=0
    while ( f(i,j) >0 ):
      x+= f(i,j)
      j+=1

(f some unimportant function.)

I came up with something like this:

a= [x| i<-[0..100], let s = takeWhile (\k-> (f i k > 0)) [0..],
        j<- s, let x = f i j ]

Then Sum a does the work, but I need to compute f i j two times which is a little bit redundant.

Can this be done with f computed only once or some better codes that run faster?

Upvotes: 0

Views: 206

Answers (2)

ryachza
ryachza

Reputation: 4540

For fun the most direct translation I could come up with was:

f i j = 100 - i - j

test x =
  foldr (\i ->
      foldr (\j g ->
          let y = f i j in
          if y > 0 then g . (+ y) else id
        ) id [0..]
    ) x [0..100]

x = test 0

Or with some helpers:

f i j = 100 - i - j

for :: (Enum i) => i -> i -> (i -> a -> a) -> a -> a
for i1 i2 f x = foldr f x [i1..i2]

while :: i -> (i -> i) -> (i -> Bool) -> (i -> a -> a) -> a -> a
while i s p f x =
  foldr (\i g x ->
      if p i then g (f i x) else x
    ) id (iterate s i) x

test =
  for 0 100 $ \i ->
    while 0 (+ 1) (\j -> f i j > 0) $ \j x ->
      x + f i j

x = test 0

Upvotes: 0

crockeea
crockeea

Reputation: 21811

Here's a way that only computes f once for each pair:

inner i = sum $ takeWhile (> 0) $ map (f i) [0..]
x= sum $ map inner [0..100]

I dislike list comprehensions, especially for more complex expressions, so I found your solution difficult to read. The primary difference is that instead of storing a list of js such that f i j > 0, I stored the actual function value. This does no more work due to laziness.

Upvotes: 2

Related Questions