# Square Root by Newton's Method
# Functional Programming Example using Python 3.6+ Nested Functions
# H. Conrad Cunningham, Professor Computer and Information Science
# University of Mississippi

# Developed for CSci 658, Software Language Engineering, Spring 2018

# 34567890123456789012345678901234567890123456789012345678901234567890

# 2018-03-17: Developed from 2015 Elixir version 

# This square root modulw is adapted from a 2015 Elixir version, which
# itself is adapted from a 2013 Lua version, which was in turn adapted
# from the Scheme code in section 1.1.7 of Abelson and Sussman's
# Structure and Interpretation of Computer Programs (SICP) textbook.

# Function sqrt computes the square root of its argument x using
# Newton's method.

def sqrt(x):
    def square(x):
        return x * x
    def good_enough(guess,x):
        return abs(square(guess) - x) < 0.001
    def average(x,y):
        return (x + y) / 2
    def improve(guess,x):
        return average(guess,x/guess)
    def sqrt_iter(guess,x):
        if good_enough(guess,x):
	        return guess
        else:
            return sqrt_iter(improve(guess,x),x)
    if x >= 0:
        return sqrt_iter(1, x)
    else:
        print(f'Cannot compute square root of negative number {x}')

if __name__ == '__main__':
    print(f'sqrt(-1) is {sqrt(-1)}')
    print(f'sqrt(0)  is {sqrt(0)}')
    print(f'sqrt(1)  is {sqrt(1)}')
    print(f'sqrt(2)  is {sqrt(2)}')
    print(f'sqrt(3)  is {sqrt(3)}')
    print(f'sqrt(4)  is {sqrt(4)}')
    print(f'sqrt(9)  is {sqrt(9)}')
    print(f'sqrt(16) is {sqrt(16)}')
