# pythonDemo.py - Some tricky examples
# Python 3 code. Full documentation at http://aipython.org

# Artificial Intelligence: Foundations of Computational Agents
# http://artint.info
# Copyright David L Poole and Alan K Mackworth 2023.
# This work is licensed under a Creative Commons
# Attribution-NonCommercial-ShareAlike 4.0 International License.
# See: http://creativecommons.org/licenses/by-nc-sa/4.0/deed.en

# to run this:
# ipython -i pythonDemo.py

##### Some features adopted from functional programming & Haskell
a1 = lambda x:x+1
a17 = a1(7)
lzy = lambda: (1000000**1000000) % 37   # % is `mod`
# try  lzy()    # might not be lazy! (Try adding 00 to the exponent)

odd = lambda n: n % 2 ==1
def even(n): return n % 2 == 0
l1 = [x*x for x in range(10) if odd(x)] # list
s1 = {x*x for x in range(10) if odd(x)} # set
d1 = {x*x:x for x in range(10) if odd(x)} # dictionary
g1 = (x*x for x in range(10) if odd(x)) # generator

a = ["a","f","bar","b","a","aaaaa"]
ind = {a[i]:i for i in range(len(a))}
ind['b']

####### What do the following return? Why?

fun_list1 = []
for i in range(5):
    fun_list1.append(lambda e: e+i)

# Try:
# [f(10) for f in fun_list1]

# i=100
# [f(10) for f in fun_list1]

fun_list2 = []
for j in range(5):
    fun_list2.append(lambda e,jv=j: e+jv)

j=555

# [f(10) for f in fun_list2]

fun_list3 = []
for j in range(5):
    def fun3(e,jv=j):
        return e+jv
    fun_list3.append(fun3)

# [f(10) for f in fun_list3]

fun_list4 = [lambda e: e+k for k in range(5)]
k=5555

# [f(10) for f in fun_list4]

fun_list5 = [lambda e,iv=i: e+iv for i in range(5)]

# [f(10) for f in fun_list5]


########## Python can be programmed to act lazily ##########
#  a generater of the list of all numbers from n
def nums_from(n):
    while True:
         yield n
         n=n+1

# a list of the first n elements from gen
def take(n,gen):
    res = []
    for i in range(n):
        res.append(next(gen))
    return res

# a generator of the first n elements from gen
def takel(n,gen):
    for i in range(n):
        yield next(gen)

# Try:
# take(10,nums_from(100))
# list(takel(10,nums_from(100)))

# [n*n for n in take(10,nums_from(100))]
# [n*n for n in takel(10,nums_from(100))]
# list(takel(10, (n*n for n in nums_from(100))))
# takel(10, (n*n for n in nums_from(100)))
# take(10, takel(10000000000000, (n*n for n in nums_from(100))))
# take(10, iter(take(2000000, (n*n for n in nums_from(100)))))    #iter creates an iterator from a list
# list(takel(10, [n*n for n in nums_from(100)]))  # doesn't halt!


