python->方案转换的问题

时间:2008-12-06 23:58:09

标签: python arrays scheme

我目前正在尝试使用方案语义编写Python程序,以便稍后可以将其转换为Scheme而不依赖于许多Pythonic的东西。

我正在尝试使用*,深度优先和广度优先搜索算法来解决滑动拼图问题(其中您有9个插槽和8个拼贴排列在正方形中)。我在11年前在Lisp的一些AI课上做过这个,但基本上当时我不知道lisp,我全心全意地讨厌它,只有回想起来我才意识到我在Lisp中编写了“C”。教授在这件事上没有帮助。

我有一个python函数,可以轻松交换两个tile:

def swap(p, (r1, c1), (r2, c2)):  
    # Swaps *any* two locations and returns new configuration  
    # Does not concern itself with zero location, etc  
    # Not sure how to do this functionally  
    p_p = p[:]  
    temp = p_p[r1][c1]  
    p_p[r1][c1] = p_p[r2][c2]  
    p_p[r2][c2] = temp  
    return p_p  

我想把它变成你可能在SICP中找到的东西,避免副作用等。

但这提出了一个问题。我在SICP中读到的所有东西都是通过递归循环。在常量时间访问数组/向量/列表时没有看到任何内容。我可以想象一种循环/递归方式来读取一个元素,但我发现很难想象一种方法来创建一个新的列表,其中某个元素被更改,而不会调用副作用产生像set!这样的东西,而不是诉诸于疯狂如果/ then / else有关应该更改哪个元素的子句。当考虑二维阵列时,这当然会变得更加混乱。在这种情况下,使用python的解决方案是显而易见的,因为它对多维数组的本机支持。

在C / C ++ / Python / Matlab / Lua /其他任何地方,通过[i]语法访问列表/数组很容易,直接转换为下面某处的面向硬件的指针查找。考虑到SICP版本的方案中定义的原子操作,我看不出方案如何做到这一点,这些操作看起来都非常以循环和搜索为导向。向量和列表数组访问函数如何工作以获得恒定的时间访问? (我在这里总是新手,所以我不确定我会谈论什么功能)。在秘密访问的某个地方是否有C或汇编库?在方案中是否有任何固有的常量时间语义可用于列表/数组/向量访问,这将允许我在Python中使用该成语的无罪方式?

如何使用Schemish语义在python中重写上述函数?我如何在Scheme中重写上述函数?

4 个答案:

答案 0 :(得分:4)

您发现您的初始问题是尝试在Lisp中编写C语义。是不是重复错误尝试在python中编写方案语义?我总是尝试将语言X作为一种范式学习,就像语言一样,并以最简单的方式写作。

如果这是一个你知道要迁移的商业应用程序,这可能是合理的,但除此之外,我只是在计划中将其写入。

答案 1 :(得分:2)

大约一年前,我在Lisp写了一个8-puzzle解算器。我刚刚使用了3个列表的列表,每个子列表中有3个元素是数字。这不是固定时间,但它是便携式的。

无论如何,如果你真的对这个功能感兴趣(Scheme不需要你),最简单的方法是创建一些辅助函数,它们将获得给定row / col的特定值并'set'一个值给定行/列。设置操作不是修改原始数据结构,而是基于旧状态构造新状态。

然后,您可以根据这些get和set操作编写交换操作。这是我一年前在Common Lisp中写的内容,但它很容易转换为Scheme:

; getval
;
; This function takes a position (r . c) where and returns the corresponding
; number in the 8-puzzle state. For example, if you wanted (1 . 2) from
; ((1 2 3) (4 5 6) (7 8 9)), the value would be 6. The r and c values begin
; at 0.
;
; parameters:  pos    The position to get
;              state  The 8-puzzle state
; returns:     The value at pos in state
(defun getval (pos state)
  (if (null state) 'no-value
      (if (= 0 (car pos))
      (if (= 0 (cdr pos))
          (caar state)
          (getval (cons (car pos) (- (cdr pos) 1)) (list (cdar state))))
      (getval (cons (- (car pos) 1) (cdr pos)) (cdr state)))))

; setval
;
; This function returns a state where the value at pos is replaced by val.
; Like getval, this function is zero-based. Accessing beyond the size of
; the state is undefined (and probably broken)
;
; parameters:  pos    Position to set
;              val    Value to set
;              state  State to modify
; returns:     New state where pos is val
(defun setval (pos val state)
  (if (null state) '()
      (if (= 0 (car pos))
      (if (= 0 (cdr pos))
          (cons (cons val (cdar state)) (cdr state))
          (let ((temp (setval (cons (car pos) (- (cdr pos) 1)) val
                  (cons (cdar state) (cdr state)))))
        (cons (cons (caar state) (car temp)) (cdr temp))))
      (cons (car state) (setval (cons (- (car pos) 1) (cdr pos)) val (cdr state))))))

; state-swap
;
; This function takes a state and two positions and returns a new state with
; the values in those two positions swapped.
;
; parameters:  state  State to swap within
;              a      Position to swap with b
;              b      Position to swap with a
; return:      State with a swapped with b
(defun state-swap (state a b)
  (let ((olda (getval a state)) (oldb (getval b state)))
    (setval a oldb (setval b olda state))))

答案 2 :(得分:1)

这是实现它的一种方法。使用将应用适当映射的函数重新创建列表。

def swap(p, (r1,c1), (r2,c2)):
    def getitem(r,c):
        if (r,c) == (r1,c1): return p[r2][c2]
        elif (r,c) == (r2,c2): return p[r1][c1]
        return p[r][c]
    return [ [getitem(r,c) for c in range(len(p[0]))] for r in range(len(p)) ]

你甚至可以更进一步,使函数成为实际的接口,其中每个交换只返回一个函数,该函数在传递给下面的函数之前进行适当的转换。不是特别高效,而是一种相当简单的功能方法,可以省去令人讨厌的可变数据结构:

def swap(f, (r1,c1), (r2,c2)):
    def getitem(r,c):
        if (r,c) == (r1,c1): return f(r2,c2)
        elif (r,c) == (r2,c2): return f(r1,c1)
        return f(r,c)
   return getitem

l=[ [1,2,3], [4,5,6], [7,8,0]]
f=lambda r,c: l[r][c]    # Initial accessor function
f=swap(f, (2,1), (2,2))  # 8 right
f=swap(f, (1,1), (2,1))  # 5 down
print [[f(x,y) for y in range(3)] for x in range(3)]
# Gives: [[1, 2, 3], [4, 0, 6], [7, 5, 8]]

答案 3 :(得分:0)

很酷,谢谢你的lisp代码。我需要研究它以确保我得到它。

至于第一个答案,我第一次在lisp中“写c”,因为这是我知道如何编程的唯一方式,并且没有线索为什么有人会使用lisp。这一次,我一直在玩计划,但是想要使用python,所以如果我遇到了什么我可以“欺骗”并使用一些pythonish,然后等待usenet的答案继续问题的下一部分