#haskell
#haskell
Вопрос:
Я пишу трассировщик лучей на Haskell, и в настоящее время я определяю свою сцену в коде следующим образом:
(Scene [(Sphere (Vec3 1 0 0) 4 (PhongMaterial (color 1 0 0) (color 1 1 1) 4))]
[(PhongLight (Vec3 0 0 0) (color 1 1 1) (color 1 1 1))])
Это действительно хорошо работает с точки зрения выразительности, и это здорово, потому что мне не нужно писать какой-либо синтаксический анализатор, но это означает, что мне приходится перекомпилировать каждый раз, когда я хочу отобразить другую сцену. Я пришел к Haskell через Lisp, где это было бы просто (загрузить файл, оценить содержимое и затем отобразить результат), но я признаю, что у Haskell есть черты, которые делают это если не невозможным, то очень сложным.
Есть ли у кого-нибудь из вас, более опытных хаскеллеров, какие-либо предложения по наилучшему способу решения этой проблемы? В идеальном мире у меня был бы некоторый файл, внешний по отношению к моему коду, который определял бы сцену в синтаксисе Haskell, который я мог бы загрузить; в наименее идеальном мире я бы писал синтаксический анализатор в Parsec. Спасибо!
Комментарии:
1. Не могли бы вы рассказать немного больше об этой
color
функции? Как правило, в Haskell есть много хороших библиотек для сериализации и десериализации данных различными способами, но сериализация и десериализация кода могут быть немного сложнее. Если эти вызовыcolor
могут быть заменены данными, которые они создают вместо этого, это значительно упрощает ситуацию.2. Является
color 1 1 1
ли вызов функцией? Можно ли изменить его на конструктор (чтобы это были данные)?3. Вы хотите интерпретировать все или вы хотите скомпилировать средство визуализации и динамически загружать сцену?
4. В
color
настоящее время функция является просто удобной функцией для более длинного и сложного конструктора данных, но я был бы готов пожертвовать некоторой краткостью ради простого решения.5. @HeinrichApfelmus: Я хочу скомпилировать средство визуализации и динамически загружать сцену из средства визуализации.
Ответ №1:
Если вы убедитесь, что все ваши data
экземпляры являются экземплярами Read
(… deriving Read
), тогда вы можете просто read them :: Withatypeifnecessary
.
Промежуточным решением было бы использовать json; синтаксический анализ проще, чем использование Parsec, но, конечно, это немного сложнее, чем просто read
в коде.
Обновление: если есть функции, не являющиеся конструкторами, read
подход не будет работать.
Комментарии:
1. Какова ваша история для
color 1 0 0
битов, которые на самом деле являются вызовом функции (не конструктора)?2. Два действительно хороших варианта. Я думаю, что пока я пойду по пути чтения. Спасибо!
Ответ №2:
В этом случае, не могли бы вы просто использовать read
(предполагая, что все работает deriving Read
). Это, очевидно, немного неуклюже, но, скорее всего, это, вероятно, сработает (и это меньше работы, чем идти по маршруту parsec).
Комментарии:
1. Он обрабатывает дополнительные круглые скобки. Попробуйте. =)
Ответ №3:
Как насчет использования интерпретатора haskell, такого как подсказка? По общему признанию, это не так просто, как в lisp, и вам нужно быть особенно осторожным, чтобы скомпилировать свой рендерер с теми же модулями, которые вы используете для описания своих сцен, но все же это может работать нормально, хотя на самом деле это не способ делать вещи на Haskell.
main :: IO ()
main = do
[a] <- getArgs
r <- runInterpreter (loadScene a)
case r of
Left err -> printInterpreterError err
Right scene -> raytrace scene
loadScene :: Filepath -> Interpreter ()
loadScene fn = do
loadModules [fn]
eval "name_of_variable_describing_scene_in_my_source"