Хранить внешние данные в модулях Guile?

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

  1. Сохраните проанализированные данные в виде сложной структуры списка и запишите их в файл SCM с помощью write. Тогда полный список можно просто прочитать, нажав read. Конечно, но... (каждый раз нужно будет читать сложное представление данных в виде списка и впоследствии формировать все записи - этого можно было бы избежать, если бы данные уже были скомпилированы)
  2. Нельзя ли как-то сохранить разобранный результат в модуле Guile? Это скомпилированный материал раз и навсегда? Однако я не могу найти правильный способ сделать это.

Упрощенный пример:

Пусть комплексные данные представляют собой одно число во внешнем файле DATA.txt:

10

Давайте создадим модуль data.scm, который считывает внешние данные, сохраняет их и экспортирует:

(define-module (data))

(export DATA)

(define DATA (with-input-from-file "DATA.txt" read))

Давайте проверим этот подход с помощью test.scm:

(add-to-load-path (dirname (current-filename)))

(use-modules (data))

(format #t "DATA: ~a\n" DATA)

ЭТО, ПОКАЗЫВАЕТСЯ, РАБОТАЕТ (автокомпиляция включена или даже используется guild compile data.scm):

$ guile test.scm
DATA: 10

Однако, когда я удаляю файл DATA.txt, возникает ошибка, поскольку в (скомпилированном) модуле данных отсутствует файл DATA.txt для чтения!

Таким образом, проблема остается: как на самом деле хранить внешние данные в модуле во время компиляции?

ЧТО РАБОТАЕТ, НО УЖАСНО!

Чтобы сгенерировать файл модуля буквально, например:

(define DATA (with-input-from-file "DATA.txt" read))

(with-output-to-file "data.scm"
  (lambda ()
    (format #t
            "(define-module (data))

(export DATA)

(define DATA ~a)\n"
            DATA)))

Этот подход подобен использованию макросов C без использования преимуществ макросов схемы (т.е. синтаксиса). Неужели не существует элегантной схемы?

При первом импорте модуля Guile обычно компилирует его и кэширует скомпилированную версию для повторного использования. Или вы можете скомпилировать его заранее с помощью guild compile. Поэтому я бы рассмотрел ваш второй вариант (поместив ваши данные в отдельный модуль и импортировав их там, где это необходимо)

Shawn 19.06.2024 20:47

Спасибо, я понимаю вашу точку зрения. Мой вопрос, возможно, был нечетко сформулирован. Теперь я также привел пример в надежде показать, в чем проблема.

Jan Šmydke 20.06.2024 00:50

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

Shawn 20.06.2024 04:08

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

Jan Šmydke 20.06.2024 14:40
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Используя макросы Lispy, файл модуля data.scm можно закодировать следующим образом:

(define-module (data))

(export DATA)

(define-macro (define-get name file)
  `(define ,name
     ,(with-input-from-file file read)))

(define-get DATA "DATA.txt")

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

И до сих пор не понимаю, почему оригинал (define DATA ...) не работал, поскольку я всегда думал, что в схеме аргументы сначала оцениваются, прежде чем использоваться.

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

Вот пример того, как это сделать с помощью макроса syntax-case:

$ cat foo.scm
(define-module (foo)
  #:export (data))

(use-modules (ice-9 textual-ports))

(define-syntax include-file
  (lambda (stx)
    (syntax-case stx ()
      ((_ name)
       (let ((file-contents
              (call-with-input-file (syntax->datum #'name) get-string-all)))
         (datum->syntax #f file-contents))))))

(define data (include-file "./data.txt"))
$ cat data.txt
blah
$ sudo cp foo.scm /usr/share/guile/site/3.0/foo.scm
$ sudo guild compile -o /usr/lib64/guile/3.0/ccache/foo.go foo.scm
$ cd ..
$ guile
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (use-modules (foo))
scheme@(guile-user)> data
$1 = "blah\n"

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

Ооо, оказывается, у хитрости есть оценка-когда. Возможно, здесь будет другой подход...

Shawn 20.06.2024 21:23

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

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