Заказ кода в Clojure - PullRequest
       17

Заказ кода в Clojure

36 голосов
/ 13 июля 2009

У меня есть простая, но разочаровывающая проблема в Clojure, у меня есть функция (давайте назовем ее read-function), которая вычисляет, что пользователь хочет сделать из его ввода, затем вызывает другую функцию, которая делает это (давайте назовем это action- функция). Эта экшн-функция вызывает функцию чтения по завершении, чтобы пользователь мог выполнить другую задачу.

Теперь моя проблема в том, что, если я помещаю код для функции чтения перед кодом для функции действия, я получаю ошибку в функции чтения, говорящую, что она не знает, что такое функция действия (потому что код для это еще дальше), и если я сделаю обратное, я получаю аналогичную ошибку, очевидно, говоря, что функция чтения не может быть решена и т. д.

Есть ли простой способ исправить это?

Фактический код:

(defn ajout [botin]
  (def botin botin)
  (readCmd botin)
)

(defn readCmd [botin]
  (println "Entrez une commande svp ")
  (def botin botin)
  (let [cmd (read-line)]
    (if (.equals cmd "a") ((println "Ajout 8o") (ajout botin))
      (if (.equals cmd "e") ((println "Elim 8o") (eliminer botin))
        (if (.equals cmd "i") ((println "Imprim 8o") (imprimer botin))
          ((println "Commande invalide, nous vous rapellons que les commandes possibles sont : ") (print-les-cmd) (readCmd))))))


)

вот так я получаю сообщение об ошибке в строке (readCmd botin) в функции ajout: Не удалось разрешить символ: readCmd в этом контексте

Если я поставлю код для этих двух функций в обратном порядке, я получу сообщение об ошибке: Не удалось разрешить символ: ajout в этом контексте

Ответы [ 4 ]

63 голосов
/ 13 июля 2009

Вы можете использовать предварительные объявления в Clojure, чтобы вы могли вызывать функции, которые еще не были определены.

(declare readCmd)

должно работать!

В Clojure важен порядок, в котором вы определяете функции, функция не может вызывать другую функцию (или что-то еще), которая еще не была определена. Вот почему у нас есть предварительные декларации.

18 голосов
/ 20 июля 2009

Как уже отвечали другие, вам нужно (объявить readCmd), чтобы решить вашу непосредственную проблему.

Однако в этом коде все еще есть проблемы, поскольку он фактически реализует итеративный процесс с использованием взаимной рекурсии (readCmd -> ajout -> readCmd -> imprimer -> readCmd -> ...), который будет использовать стек и будет Вы получите переполнение стека. Лучший способ организовать это - сделать хвост readCmd рекурсивным и заставить его вызывать действия. Когда действие возвращается, хвост readCmd рекурсивно вызывает себя.

Также этот фрагмент кода:

((println "Ajout 8o") (ajout botin))

вероятно, это не то, что вы хотите сделать: он вызовет println и попытается использовать результат как функцию. Вместо этого используйте «do»:

(do (println "Ajout 8o") (ajout botin))

Вы также можете прочитать о case или cond, они упростят вложенные ifs.

Еще одна странная вещь в вашем коде

(def botin botin)

о чем речь?

11 голосов
/ 13 июля 2009

Вверху вашего кода поставьте:

(declare readCmd)
2 голосов
/ 15 августа 2015

В группе Google Clojure есть ветка, в которой приводятся некоторые интересные соображения, в частности, о том, как использование объявления может сбить некоторые инструменты в экосистеме:

нить

Конечно, можно утверждать, что хорошие инструменты должны работать со всеми конструкциями языка:)

ИМО, вы как бы привыкли к стилю снизу вверх и просто читаете в обратном порядке. Это немного другая история, когда вы рассказываете, где вы создаете вещи, а не разлагаете их.

И, конечно, как уже говорили другие, вы можете пересылать объявление с помощью

(declare my-function)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...