递归在Clojure中变为无穷且不返回值

时间:2019-05-28 23:38:59

标签: recursion clojure clojurescript maze

我是Clojure的新手。在这里,您可以看到函数fp_fun。我正在使用此函数,并且它变为无穷大。我认为它没有返回值。请让我知道答案。预先感谢

(defn fp_fun
([x y row col vec]

(if (or (< x 0) (< y 0) (>= x row) (>= y col))
  0)
(if (= vec[x y] "@") 
1)
(if (= vec[x y] "#")
0)

(def x1 (+ x 1))

(def y2 (- y 1))
(if (= ( (fp_fun x y2 row col vec)) 1  )
1)
(if (= ( (fp_fun x1 y row col vec)) 1  ) 
1)

1)
(println "!" x y)
0
) )

1 个答案:

答案 0 :(得分:3)

首先,我将应用emacs自动格式化程序,然后让我们研究这里每个表达式的含义

(defn fp_fun
  ([x y row col vec]
   (if (or (< x 0)
           (< y 0)
           (>= x row)
           (>= y col))
     0)
   (if (= vec[x y] "@")
     1)
   (if (= vec[x y] "#")
     0)
   (def x1 (+ x 1))
   (def y2 (- y 1))
   (if (= ( (fp_fun x y2 row col vec)) 1  )
     1)
   (if (= ( (fp_fun x1 y row col vec)) 1  )
     1)
   1)
  (println "!" x y)
  0) )

最初,它将不会编译,因为在主体函数主体之后有两个额外的表达式。

clojure中有两种主要形式的表达式,它们定义了它们基本看起来像的功能

((defn [args here]
   expression-that-returns-the-result-of-this-function-here)

第二种形式,如果有多种不同的参数数字调用此函数的方式

(defn
  ([one-arg]
   result-expression-here)
  ([fist-arg second-arg]
   other-result-expression-here))

两者都有一点,所以我们删除最后两个表达式:

 (println "!" x y)

0

这使我们陷入困境

(defn fp_fun
  ;; this function always takes 5 args, so prefer the basic form
  ([x y row col vec]

   ;; this first expression does absolutly nothing and it totally ignored
   (if (or (< x 0)
           (< y 0)
           (>= x row)
           (>= y col))
     0)

   ;; this next expression is also ignored, only the last value in a function determines it's result
   (if (= vec[x y] "@")
     1)

   ;; so this one does nothing as well
   (if (= vec[x y] "#")
     0)

   ;; these two define some global variables
   ;; using def inside a function is almost always better done with a let expression
   (def x1 (+ x 1))
   (def y2 (- y 1))

   ;; this will always run because none of the above statements cause the function to
   ;; stop and return it's value early.
   (if (= ( (fp_fun x y2 row col vec)) 1  )
     1)

   ;; and  then the stack will overflow before we get here
   (if (= ( (fp_fun x1 y row col vec)) 1  )
     1)
   1))

接下来,我们可以嵌套表达式,以便较早的表达式可以控制函数的结果:

 (defn fp_fun [x y row col vec]
   (if (or (< x 0)
           (< y 0)
           (>= x row)
           (>= y col))
     0
     (if (= (vec x y) "@")
       1
       (if (= (vec x y) "#")
         0
         (let [x1 (+ x 1)
               y2 (- y 1)]
           (if (= (fp_fun x y2 row col vec) 1)
             1
             (if (= (fp_fun x1 y row col vec) 1)
               1)))))))

我希望为您提供一个从中构建函数的结构,重要的是每个函数都只返回一个结果,该结果就是该函数中最后一个表达式返回的结果。因此通常该表达式中嵌套了其他表达式。

随着我们添加更多的if表达式,它开始看起来有点嵌套,并且有一个if紧跟着=的常见模式,幸运的是clojure具有cond,对于条件表达式,宏,用于清晰地表达这样的模式

 (cond
   (or (< x 0) (< y 0) (>= x row) (>= y col)) 0
   (= (str(get-in board [x y])) "@")          1
   (= (str (get-in board [x y])) "#")         0
   (= (find_path x (- y 1) row col board) 1)  1
   (= (find_path (+ x 1) y row col board) 1)  1
   (and (>= x 0) (< y col))  (if (= (find_path x (+ y 1) row col board) 1)
                               1
                               0)
   :defautl nil) ;; i'm not sure you intended to default to nil