Объясните символы Clojure

Я никогда не использую "структуру" в C++.

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

кажется, что использование структур является большим количеством синтаксического признака того, как данные будут использоваться, но я просто сделал бы класс и попытался бы сделать это явным от имени класса, или через комментарии.

, Например,

class PublicInputData {
    //data members
 };
32
задан Alex B 24 July 2009 в 05:58
поделиться

3 ответа

REPL = чтение цикла печати eval. Пройдите через процесс чтения-оценки.

READ: Clojure видит строку «(` a) », анализирует ее и в итоге получает структуру данных. Во время чтения макросы читателя раскрываются, и больше ничего не происходит. В этом случае читатель разворачивает обратную кавычку и заканчивает так:

user> (read-string "(`a)")
((quote user/a))

EVAL: Clojure пытается оценить этот объект. Правила оценки различаются в зависимости от того, на какой объект вы смотрите.

  • Некоторые объекты оцениваются как сами себя (числа, строки, ключевые слова и т. Д.).
  • Символ оценивается путем разрешения его в некотором пространстве имен для получения некоторого значения (обычно).
  • Список оценивается путем расширения списка макросов до тех пор, пока не останется никаких макросов, затем рекурсивно оценивается первый элемент в списке для получения некоторого результирующего значения , затем используется значение ] первого элемента в списке, чтобы решить, что делать. Если первое значение - это особая форма, случаются особые вещи. В противном случае первое значение обрабатывается как функция и вызывается со значениями остальной части списка (полученного путем рекурсивной оценки всех элементов списка) в качестве параметров.
  • и т. Д.

См. clojure.lang .Compiler / analysisSeq в исходном коде Clojure, чтобы увидеть правила оценки для списков, или clojure.lang.Compiler / analysisSymbol для символов. Там есть много других правил оценки.

Пример

Предположим, вы делаете это:

user> (user/a)

REPL выполняет это внутренне:

user> (eval '(user/a))

Clojure видит, что вы оцениваете список, поэтому он оценивает все элементы в списке. Первый (и единственный) элемент:

user> (eval 'user/a)
#<user$a__1811 user$a__1811@82c23d>

a не является специальной формой, и этот список не нужно расширять макросом, поэтому символ a ищется в пространстве имен user , а результирующее значение здесь - fn . Итак, вызывается fn .

Ваш код

Но вместо этого у вас есть следующее:

user> (eval '((quote user/a)))

Clojure оценивает первый элемент в списке, который сам является списком.

user> (eval '(quote user/a))
user/a

Он оценил первый элемент в этом подсписке, quote , который представляет собой особую форму, поэтому применяются особые правила, и он возвращает свой аргумент (символ a ) un- оценен.

Символ a - это значение в этом случае, поскольку fn было значением выше. Итак, Clojure рассматривает сам символ как функцию и вызывает его. В Clojure все, что реализует интерфейс Ifn , можно вызывать как fn . Так получилось, что clojure.lang.Symbol реализует Ifn . Символ, вызываемый как функция, ожидает один параметр, коллекцию, и ищет себя в этой коллекции. Он предназначен для использования следующим образом:

user> ('a {'a :foo})
:foo

Это то, что он пытается сделать здесь. Но вы не передаете никаких параметров, поэтому вы получаете сообщение об ошибке «Неверное количество аргументов, переданных в: Symbol» (он ожидает коллекцию).

Чтобы ваш код работал, вам потребуются два уровня eval . Это работает, надеюсь, вы понимаете, почему:

user> (eval '((eval (quote user/a))))
Hello, world
user> ((eval (first l)))
Hello, world

Обратите внимание, что в реальном коде использование напрямую eval обычно является очень плохой идеей. Макросы - безусловно лучшая идея. Я использую его здесь только для демонстрации.

Посмотрите Compiler.java в исходном коде Clojure, чтобы увидеть, как все это разыграется. Это не так уж и сложно.

36
ответ дан 27 November 2019 в 20:38
поделиться

Использование символа как функции - не то же самое, что его оценка. Символы как функции работают так же, как ключевые слова как функции. Как это:

user=> (declare a)
#'user/a
user=> (def a-map {'a "value"})
#'user/a-map
user=> ('a a-map)
"value"
user=>

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

Чтобы разбить уровни косвенности, давайте определим «x» как 1 и посмотрим, что произойдет:

user=> (def x 1)
#'user/x

Использование ] def , мы создали "var." Имя переменной - это символ user / x. Специальная форма def возвращает саму var в repl, и это то, что мы видим напечатанным. Давайте попробуем получить эту переменную:

user=> #'x
#'user/x

Синтаксис # ' - это макрос чтения, который говорит: «Дайте мне переменную, на которую указывает следующий символ». И в нашем случае этот символ - «х». Мы получили тот же var, что и раньше. Переменные - это указатели на значения, и их можно разыменовать:

user=> (deref #'x)
1

Но переменную нужно найти, прежде чем ее можно будет разыменовать. Именно здесь вступает в игру вызываемость символов. Пространство имен похоже на карту, где символы являются ключами, а переменные - значениями, и когда мы явно называем символ, мы неявно ищем его переменную в нашем пространстве имен. Примерно так:

user=> ('x (.getMappings *ns*))
#'user/x

Хотя, на самом деле, это, вероятно, больше похоже на это:

user=> (.findInternedVar *ns* 'x)
#'user/x

И вот мы прошли полный круг в путешествии символа без кавычек:

user=> (deref (.findInternedVar *ns* 'x))
1
user=> x
1

Однако эти двое не полностью равны. Потому что вычислитель делает это для всех символов, включая deref и * ns *.

Суть цитирования заключается в том, что вы по существу обходите весь этот механизм и просто получаете обратно простой символ. Как # ' Макрос чтения возвращает простые переменные, макросы чтения `и 'возвращают простые символы, с квалификацией пространства имен или без нее, соответственно:

user=> 'x
x
user=> `x
user/x
15
ответ дан 27 November 2019 в 20:38
поделиться

Мой ответ не соответствует ответ на методологию водопада, который вы искали, потому что я думаю, вам нужно будет изучить навыки программирования игр, прежде чем вы сможете планировать, проектировать, внедрять и тестировать его. Программирование игр ОЧЕНЬ отличается от бизнес-программирования и от целой другой области как таковой. Первое, что вам нужно будет изучить, - это язык программирования OpenGL ES . По сути, это 3D API, который позволяет рисовать трехмерные примитивы. Вам все равно нужно будет использовать это, если вы кодируете 2D-игру, поскольку это быстро из-за использования графического процессора для ускорения. В Google есть несколько хороших руководств, с которых вам следует начать.

Vector Math Если вы делаете что-либо в 3D, вам нужно будет изучить математику 3D-векторов, векторы в основном используются для всего в играх, направления взгляда камеры, положения символов, скорости, обнаружения столкновений и т. Д. 2D-векторы (x, y) минус Компонент z по-прежнему необходим для программирования 2D-игр.

Обнаружение столкновений Как я узнаю, когда мой мяч попадает в стену? Ответ - обнаружение столкновений. Существует множество форм обнаружения столкновений, таких как сфера со сферой, AABB , OOBB , выпуклая оболочка, треугольная сетка и т. Д.

AI Как заставить врага атаковать моего персонажа? Искусственный интеллект - еще одна большая область, необходимая для того, чтобы дать NPC / Врагам возможность принимать разумные решения. ИИ может быть простым, например, операторами if else, но для его эффективности обычно требуются конечные автоматы или нечеткая логика.

Поиск пути Если вы хотите переместить персонажа из точки A в точку B, избегая врагов и движущихся препятствий, вам нужно будет использовать алгоритм поиска пути. Звезда (A *) - одна из самых популярных.

График сцены Если вы хотите, чтобы на экране одновременно отображалось 10-20 + врагов, вам нужно будет закодировать граф сцены для управления динамическим отрисовкой, логикой и созданием и удалением ресурсов. Если вы не знаете, что такое полиморфизм, вам необходимо знать его, так как это важно для ваших игровых объектов, и он связан с графом сцены.

Физика Положение, скорость, ускорение, гравитация и лучи представлены с помощью векторов, и вам может потребоваться освежить свои знания математики, чтобы написать код для любой игры. Начнем со Второго закона движения Ньютона F = MA (Сила = Масса * Ускорение). Физический движок с открытым исходным кодом, такой как Bullet, ODE, Newton, Tokamak, упростит задачу, а это значит, что вам не нужно будет писать эти правила физики самостоятельно.

Objective-C ++ Это необязательно, но рекомендуется. Если вы не знаете C ++, это, по сути, смесь C ++ и Objective-C. Я предпочитаю использовать C ++ для ядра игры и программирования из-за скорости C ++ и доступности сторонних библиотек в C ++.

Звук Если вам нужен звук, вы можете просто пойти дальше и использовать простые аудиофреймы, которые предоставляет Apple, однако для трехмерного позиционного звука потребуется что-то лучшее. Я бы порекомендовал изучить FMOD SDK для iPhone. Как упоминал @Stowelly, FMOD требует лицензии на коммерческое распространение, но вы можете поискать и другие, не требующие лицензионных отчислений.


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

Вот они. некоторые известные мне игровые движки:

Unity3D Вероятно, это самый популярный из известных мне движков. Unity - это игровой движок для ПК / Mac, который позволяет писать код на Mac и компилировать для Windows / Linux / Mac OS X. Я сомневаюсь, что корпус iPhone совместим напрямую с другими платформами, я бы предположил, что вы будете ограничены iPhone, если вы начали новый проект. Однако коммерческое развертывание этого движка стоит от 199 до 399 долларов.

Cocos2D Это движок для 2D-игр с открытым исходным кодом, который может быть полезен для многих игр. Стоит взглянуть. Размещено в коде Google.

Вот еще несколько вариантов: user => ((first l))

Превратите это в:

user => (def l `(~ a 1 2))

Здесь ~ преобразует символ a в соответствующую ему переменную, а обратная кавычка делает работу без кавычек.

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

Я попытаюсь объяснить это (в надежде что мое объяснение вас больше не смущает):

user=> (def v "content")
#'user/content

-> определяет переменную в текущем пространстве имен под символом 'v (полностью квалифицированный' user / v, предполагая, что это текущее пространство имен), и связывает ее (переменная, не символ) к объекту "content".

user=> v
"content"

-> преобразует v в переменную и получает связанное значение

user=> #'v
#'user/v

-> разрешает в саму var

user=> 'v
v

-> ничего не разрешает, просто символ (к сожалению, REPL этого не указывает, печать 'v as v)

user=> `v
user/v

-> как вы уже цитировали, преобразуется в символ в текущем контексте (пространстве имен), но результатом остается символ (полностью определенный), а не var user / v

user=> '(v)
(v)

-> plain цитирование, ничего не разрешает

user=> `(v)
(user/v)

-> синтаксис-кавычка, то же самое, что и цитирование, но разрешает символы в символы, определяемые пространством имен

user=> `(~v)
("content")

-> разрешает символ в его var (который неявно разыменован), давая связанный с ним объект

7
ответ дан 27 November 2019 в 20:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: