
--- Square root v1

abs x | x < 0 = - x
abs x         = x

improve guess x = (guess + x / guess) / 2

goodEnough guess x = Main.abs (x-guess*guess)/x < 0.00001

sqrtIter guess x = if goodEnough guess x
                   then guess
                   else sqrtIter (improve guess x) x

sqrt1 x = let guess = 1
          in sqrtIter guess x


{-- To test it:

sqrt1 10

--}


--- Square root v2

sqrt2 x = let guess = 1
          in sqrtIter guess x
          where
            sqrtIter guess x = if goodEnough guess x
                               then guess
                               else sqrtIter (improve guess x) x
            improve guess x = (guess + x / guess) / 2
            goodEnough guess x = Main.abs (x-guess*guess)/x < 0.00001

{-- To test it:

sqrt2 10

--}

--- Square root v3

sqrt3 x = let guess = 1
              sqrtIter guess x = if goodEnough
                                 then guess
                                 else sqrtIter improve x
                where
                  improve = (guess + x / guess) / 2
                  goodEnough = Main.abs (x-guess*guess)/x < 0.00001
          in sqrtIter guess x


{-- To test it:

sqrt3 10

--}

--- Square root v4

sqrt4 x = let guess = 1
              improve guess =  (guess + x / guess) / 2
              goodEnough guess = Main.abs (x-guess*guess)/x < 0.00001
              sqrtIter guess = if goodEnough guess
                               then guess
                               else sqrtIter (improve guess)
          in sqrtIter guess

{-- To test it:

sqrt4 10

--}

--- Square root v4.5
--- Does not compromise efficiency as v3, or abstraction as v4.
--- Courtesy of Jacinda Moore (originally in Oz)

sqrt4' x = let guess = 1
               sqrtIter guess = if goodEnough guess
                                then guess
                                else sqrtIter (improve guess)
                 where improve guess =  (guess + x / guess) / 2
                       goodEnough guess = Main.abs (x-guess*guess)/x < 0.00001
            in sqrtIter guess

{-- To test it:

sqrt4' 10

--}

--- square root using Iterate abstraction

iterate' s isDone transform =
  if isDone s then s
  else let s1 = transform s in
           iterate' s1 isDone transform

--- Square root v5

sqrt5 x = iterate' 1.0 goodEnough improve
  where goodEnough = \g -> (Main.abs (x - g*g))/x < 0.00001
        improve = \g -> (g + x/g)/2.0

{-- Test it with:

sqrt5 10

--}


--- Square root v6

sqrt6 x = iterate' 1
                   (\g -> (Main.abs (x - g*g))/x < 0.00001)
                   (\g -> (g + x/g)/2.0) 

{-- Test it with:

sqrt6 10

--}

--- another example of using the iterate' abstraction:

factorial n = snd (iterate' (1,1)
                            (\(i,_) -> i>n)
                            (\(i,a) -> ((i+1),a*i)))

{-- Test it with:

factorial 5

--}


--- Square root v7: using infinite lists, map, compose

sqrt7 x = head (dropWhile (not . goodEnough) sqrtGuesses)
   where
      goodEnough guess = Main.abs (x - guess*guess)/x < 0.00001
      improve guess = (guess + x/guess)/2.0
      sqrtGuesses = 1:(map improve sqrtGuesses)


{-- To test it:

sqrt7 10

--}

--- Square root v8: using infinite lists, iterate, compose

sqrt8 x = head (dropWhile (not . goodEnough) sqrtGuesses)
   where
      goodEnough guess = Main.abs (x - guess*guess)/x < 0.00001
      improve guess = (guess + x/guess)/2.0
      sqrtGuesses = iterate improve 1


{-- To test it:

sqrt8 10

--}

--- Square root v9: using infinite lists, iterate, anonymous functions

sqrt9 x = head (dropWhile (\g -> (Main.abs (x - g*g))/x >= 0.00001)
                          (iterate (\g -> (g + x/g)/2) 1))


{-- To test it:

sqrt9 10

--}
