Рекурсия становится бесконечной в 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
) )
Учебная записка [Medium] Leetcode#22 Generate Parentheses
Учебная записка [Medium] Leetcode#22 Generate Parentheses
На этот раз мы собираемся решить еще одну классическую проблему, связанную с парными скобками, так называемую генерацию скобок.
1
0
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Для начала я применю автоматическое форматирование 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

Привет, спасибо за ваш ответ, но что, если я добавлю 4 оператора if, и он снова войдет в цикл for. Не могли бы вы сообщить мне? (defn find_path [x y row col board] (if (or (< x 0) (< y 0) (>= x row) (>= y col)) 0 (if (= (str(get-in board [x y])) "@") 1 (if (= (str (get-in board [x y])) "#") 0 (if (= (find_path x (- y 1) row col board) 1) 1 (if (= (find_path (+ x 1) y row col board) 1) 1 (if (and (>= x 0) (< y col)) (if (= (find_path x (+ y 1) row col board) 1) 1 0) )))))))

Dev Budd 29.05.2019 07:12

Просто еще одна вещь, что у меня все еще есть та же проблема. Если я добавлю еще одно условие, он перейдет в бесконечный цикл. Решение, которое вы мне дали в первый раз, сработало. В конце концов после этого, если я добавлю еще одно выражение, оно переходит в бесконечный цикл. то же самое касается решения, которое вы дали мне прямо сейчас

Dev Budd 29.05.2019 19:25

Другие вопросы по теме