Brain going crazy with recursive functions
Lie Ryan
lie.1296 at gmail.com
Sun Dec 7 21:07:56 CET 2008
On Sat, 06 Dec 2008 23:33:35 -0800, 5lvqbwl02 wrote:
> I'm trying to solve the 9-tile puzzle using as functional an approach as
> possible. I've recently finished reading SICP and am deliberately
> avoiding easy python-isms for the more convoluted scheme/functional
> methods. The following function is trivial to do with for loops and
> directly accessing arrays with [] syntax. I'm trying to limit myself to
> the types of idioms/semantics one finds in minimal scheme, such as in
> SICP. I want eventually to port this to scheme, but I know python
> better, so that's where I'm starting.
>
> My current problem is the following. The 9-tile puzzle consists of a
> list of lists like this [[1,2,3],[4,5,6],[7,8,0]], where the numbers can
> be jumbled up. I'm looking for the location of the zero using *only*
> recursion and operators that are similar to car/cdr. The return value
> should be the row,col of the zero. For example above the
> return value would be (2,2).
>
> I'm also trying to define a single "linear_search(...)" function which
> does the search for within the row (an inner list above) and within the
> whole list. linear_search takes as an argument a "truth_function"
> which does the actual work. What's tricky is that the truth function
> for the array-as-a-whole is also the linear_search for a row. Once I'm
> in linear_search for the array, I also call linear_search for each
> row.
>
> The problem is the line where it says acc.insert(0,idx) looks fishy to
> me. It works fine and returns the row,col of the location of the zero
> tile, but it seems to be mutating a variable, and that's the thing I'm
> trying to avoid. In a sense, it's not hard enough and python is making
> this too easy :) (although it took a bit of mind-wrenching to get to
> this point. Recursion makes you either dumber or smarter, I'm not sure
> which).
>
> How do I accumulate the inner value of the search so it pops out at the
> end, without resorting to a mutable variable? I did a bit of search and
> the word "monad" came up, but I'm not sure what that is (I know it
> relates to haskell and some other purely functional stuff, but
> I get very lost when trying to read that stuff).
>
>
>
>
> def linear_search(array, truth_func, acc):
> # Goes through each element of array and applies truth_func. #
Returns
> index if found, otherwise returns None def linear_search_iter(idx,
> truth_func, arr, acc):
> if arr:
> tf = truth_func(arr[0])
> if tf or type(tf) is int:
> acc.insert(0,idx)
> return idx, acc+[idx]
> else:
> return linear_search_iter(idx+1,
truth_func, arr[1:], acc)
> return linear_search_iter(0, truth_func, array, acc)
>
>
>
> def locate_zero(p):
> # Locates empty tile. Returns (r,c) tuple def find_zero_in_row
(row):
> return linear_search(row, lambda x: x==0, acc)
>
> acc = []
> ls = linear_search(p, find_zero_in_row, acc) print acc
> return acc
>
> locate_zero([[5, 3, 4], [2, 0, 1], [8, 6, 7]]) correctly returns (1,1)
In most functional languages, their natural data types differs. For
example, Haskell's list is a linked list, which if expressed in python
would look like this:
Python: [1, 2, 3, 4, 5]
Haskell-in-Python: [1, [2, [3, [4, [5, []]]]]]
linked list is more natural to use with recursive functions, so your
locate zero would be like this:
def search_tile(row, depth = 0):
head, tail = row
if head == 0:
return depth
elif len(tail) == 0:
return None
else:
return search_tile(tail, depth + 1)
def search_row(grid, depth = 0):
head, tail = grid
st = search_tile(head)
if st is not None:
return depth, st
elif tail == []:
return None
else:
return search_row(tail, depth + 1)
Now, you noticed that lots of the code is similar, we want to generalize
it. It's easy:
def search_linear(list_, checker, depth = 0):
head, tail = list_
if checker(head):
return depth, () if checker(head) is True else checker(head)
# I intentionally doesn't factor out checker(head)
# as most functional language would automatically
# do so because side-effect is impossible
elif tail == ():
return ()
else:
return search_linear(tail, checker, depth + 1)
data = (1, (2, (3, (0, ()))))
print search_linear(data, lambda x: x == 0)
# (3, ())
data = (0, (2, (3, (4, ()))))
print search_linear(data, lambda x: x == 0)
#(0, ())
data = (1, (2, (3, (4, ()))))
print search_linear(data, lambda x: x == 0)
#()
data = ((5, (3, (4, ()))), ((2, (0, (1, ()))), ((8, (6, (7, ()))), ())))
print search_linear(data, lambda row: search_linear(row, lambda tile:
tile == 0))
#(1, (1, ()))
More information about the Python-list
mailing list