How to implement a conditional interrupt loop in Haskell

I want to find out the first n satisfying f (n) = \ sum_ {k = 1} ^ {n} {1 / (k * k + 2k)}> = 2.99 / 4.0. This is simple and easy material if I use another language, for example, c / C ++, but I do not know how to implement it in Haskell.

#include <iostream>
long double term(int k) { return 1.0/(k*k+2.0*k); }
int main() {
    long double total = 0.0;
    for (int k=1;;k++) {
        total += term(k);
        if (total>=2.99/4.0) {
            std::cout << k << std::endl;
            break;
        }
    }
    return 0;
}

I used dropWhile with an ordered list and took 1 to select the first.

term k = 1.0/(k*k+2.0*k)
termSum n = sum $ take n $ map term [1..]
main = do
  let [(n,val)] = take 1 $ dropWhile (\(a,b)->b <= 2.99/4.0) $ map (\n->(n,termSum n)) [1..]
  print n

I know this is terrible. What is the best and most intuitive way to write this?

Re: Thanks for the great answers! The one that uses the fix function seems to be the fastest on my machine (Redhat 6.4 64 bit / 80 GB of memory)

method # 0 accept 1 and dropWhile (my initial implementation)

threshold=0.74999         n=99999     time=52.167 sec

method # 1 using the fix function

threshold=0.74999         n=99999     time=0.005 sec
threshold=0.74999999      n=101554197 time=1.077 sec
threshold=0.7499999936263 n=134217004 time=1.407 sec

method # 2 works back

threshold=0.74999         n=99999     time=0.026 sec
threshold=0.74999999      n=101554197 time=21.523 sec
threshold=0.7499999936263 n=134217004 time=25.247 sec

method # 3 the imperative way

threshold=0.74999         n=99999     time=0.008 sec
threshold=0.74999999      n=101554197 time=2.460 sec
threshold=0.7499999936263 n=134217004 time=3.254 sec

RERE: , , (, ), 0.7499999936264... . , f (n) 0.7499999936264, , 150 000 000, ! [f (n) =\frac_ {3n ^ 2 + 5n} ^ {4n ^ 2 + 12n + 8}]. Integer Int, . , , 0.7499999936264...?

+4
3

, fix :

import Data.Function (fix)

term k = 1.0 / (k*k+2.0*k)

main = print $ fix (\f total k ->
                      let new = total + term k
                      in if new >= 2.99/4.0 then k else f new (k+1)
                   ) 0 1
+5

:

main = print k where
  k = 1 + length (takeWhile (< (2.99/4)) partialSums)
  partialSums = scanl1 (+) terms
  terms = [ 1.0/(k*k+2.0*k) | k <- [1..] ] 

:

terms - , Haskell , , :

λ terms = [ 1.0/(k*k+2.0*k) | k <- [1..] ] :: [Double]
λ take 5 terms
[0.3333333333333333,0.125,6.666666666666667e-2,4.1666666666666664e-2,2.857142857142857e-2]
λ :p terms
terms = 0.3333333333333333 : 0.125 : 6.666666666666667e-2 :
        4.1666666666666664e-2 : 2.857142857142857e-2 : (_t5::[Double])

partialSums - , terms ( scanl1). , termSum:

λ partialSums = scanl1 (+) terms
λ take 5 partialSums 
[0.3333333333333333,0.4583333333333333,0.525,0.5666666666666667,0.5952380952380952]

takeWhile (< (2.99/4)) partialSums, , terms :

λ length (takeWhile (< (2.99/4)) partialSums)
398

, , 398 terms , 2.99 / 4, 399- :

λ sum (take 398 terms) < 2.99/4
True
λ sum (take 399 terms) < 2.99/4
False

, , 397- (, 0) 398- :

λ partialSums !! 397 < 2.99/4
True
λ partialSums !! 398 < 2.99/4
False
+7

, , , c/++

, .

import Prelude hiding (break)
import Data.IORef
import Control.Monad.Cont
import Data.Foldable
import Control.Monad (when)

-- long double term(int k) { return 1.0/(k*k+2.0*k); }
term :: Int -> Double
term k = 1.0/(k'*k'+2.0*k')
   where k' = fromIntegral k

-- int main() {
main :: IO ()
main = flip runContT return $ do
   -- long double total = 0.0;
   total <- lift $ newIORef (0.0 :: Double)
   -- for (int k=1;;k++) {
   callCC $ \break ->
      for_ [1..] $ \k -> do
         -- total += term(k);
         lift $ modifyIORef total (+ term k)
         -- if (total>=2.99/4.0) {
         totalV <- lift $ readIORef total
         when (totalV >= 2.99/4.0) $ do
            -- std::cout << k << std::endl;
            lift $ print k
            -- break;
            break ()

, , . , , , , Haskell .

This simply leads to a non-idiomatic Haskell, which is not that difficult to read or write than the source code. After all, what is a callCCor two between friends? :-P

+5
source

Source: https://habr.com/ru/post/1687901/


All Articles