2015-10-13 2 views
0

Как закодировать следующий псевдокод в Haskell?Пока в петле в Haskell

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

(. f некоторые неважная функция)

я придумал что-то вроде этого:

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

Затем Sum a делает работу, но мне нужно вычислить f i j два раз, что является немного избыточно.

Можно ли это сделать с помощью f, рассчитанного только один раз или несколько лучших кодов, которые работают быстрее?

ответ

2

Вот способ, который только вычисляет f один раз для каждой пары:

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

Мне не нравится списковые, особенно для более сложных выражений, так что я нашел ваше решение трудно читать. Основное отличие состоит в том, что вместо хранения списка j s, такого как f i j > 0, я сохранил фактическое значение функции. Это не делает работу из-за лени.

0

Для развлечения самый прямой перевод я мог придумать было:

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 

Или с некоторыми помощниками:

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