LINUX.ORG.RU

Модульность-3

 , ,


2

4

Продолжаю мучаться с системой модулей. Уже почти в депрессию впал - настолько это оказалось трудно.

Как будет устроен файл в Л2

Кусок кода делится на интерфейс и реализацию. Интерфейс и реализация находятся в разных файлах (как в С). Сборка происходит путём построения графа «зависимых действий».

Структура файла примерно такая:

// -*- для_чтения : "зависимое_действие1 ... зависимое_действиеN"; -*-
пространство_имён ИМЯ;
зависит_от зависимое_действие1 ... зависимое_действиеN ; 
... собственно код ... 

В общем-то это похоже на C с его инклюдами.

Зависимые действия

Зависимое действие - это файл (цель) и указание, что с ним нужно сделать. Что можно сделать?

1. Прочитать - это означает, что файл будет распарсен и записан куда-то в память.

2. Загрузить - это означает, что он будет откомпилирован и динамически слинкован. В ходе этого процесса будут (пере)определены описанные в файле функции и типы и выполнены команды инициализации.

Зависимости в С и в Лиспе

И вот тут у меня вопрос. В С просто указывается имя файла, а дальше система сама ищет его по путям.

В лиспе же есть «системы», хотя их надо бы назвать «модулями».

Система в лиспе является набором файлов и в то же время единицей зависимостей для сборки образа. Внутри системы - свои зависимости между файлами.

Лисп ищет систему (по путям или другим способом). Внутри системы имена файлов заданы жёстко.

Иллюзия циклических ссылок

Сравнивая работу в Лиспе и в Дельфи, я увидел, что в Дельфи работать намного удобнее. Мне казалось, что дело в циклах, и я даже многих обругал. Но я ошибался. В Дельфи нет циклических ссылок.

unit b; interface uses a; 
end. {EOF}

unit a; interface ; implementation uses b; 
end. {EOF}

Казалось бы, это циклическая зависимость. На самом же деле Дельфи компилирует интерфейс и реализацию отдельно и необязательно сразу, а зависимость возможна только от интерфейса. Поэтому это _не_ циклическая зависимость.

В Лиспе тоже надо отделить интерфейс от реализации системы

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

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

А что делать в Л2

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

Вижу два варианта:

1. Сделать как в С - единицей сборки и зависимости является отдельный файл, который ищется по помойке путей. Тут очевидно вылезает проблема уникальности имён. Я на С больших проектов не писал, может я чего-то не знаю о том, как решается эта проблема?

2. Сделать как в лиспе, т.е. ввести два уровня иерархии - систему и файл. Система содержит свой файл .asd. Но! Важное отличие от лиспа состоит в том, что система не является единицей сборки, а служит лишь для поиска файлов. Например, если мы нашли где лежит mysystem.asd, то файл mysystem.myfile.л2 находится там же. А, скажем, mysystem/dir1/f2.л2 - находится в подкаталоге dir1.

Зависимости же задаются в виде

действие(система.файл_внутри_системы)

а действие может быть «прочитать» или «загрузить». Если в системе принято стандартом хранить интерфейс в файле интерфейс.л2, то построить зависимость от интерфейса легко, зная только имя системы.

При этом где-то должно храниться знание о том, где лежит данная система. Но в asdf эта задача уже решена (даже слишком уж навороченно решена).

Собственно и вопрос - надо ли морочиться с «системами» или достаточно файлов? И может быть, кто-нибудь может это соотнести с другими языками (не знаю, как это сделано в Java и C#).

★★★★★

Ответ на: комментарий от den73

Мне точно не понравилось количество неоднозначностей, которое там можно ввести, и количество способов, которыми это можно сделать.

Какие неоднозначности? Ты вот это читал?

https://docs.racket-lang.org/guide/units.html?q=units

anonymous ()
Ответ на: комментарий от anonymous

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

den73 ★★★★★ ()
Ответ на: комментарий от anonymous

ракетка классная, ага -- в плане поддержки "языковых модулей"

вот пример откопал про реализацию текстовой игрушки (текстовые адвентюры, Interactive Fiction типа Zork-а)

смотреть следует исходники к статье, шаг за шагом. там происходит постепенный рефакторинг как демонстрация language-oriented подхода: разрабатываются модули для управления миром, и описания мира, движка игры. сначала монолитно, потом разделяют монолит на модули с #lang racket, потом #lang s-exp «txtadv.rkt» и свой reader, потом свой отдельный DSL и парсер.

в итоге получается вики-подобное

#lang txtadv

===VERBS===

north, n
 "go north"

south, s
 "go south"

east, e
 "go east"

west, w
 "go west"

up
 "go up"

down
 "go down"

in, enter
 "enter"

out, leave
 "leave"

get _, grab _, take _
 "take"

put _, drop _, leave _
 "drop"

open _, unlock _
 "open"

close _, lock _
 "close"

knock _

quit, exit
 "quit"

look, show
 "look"

inventory
 "check inventory"

help

save

load


===EVERYWHERE===

quit 
 (begin
  (printf "Bye!\n")
  (exit))

look 
 (show-current-place)

inventory 
 (show-inventory)

save
 (save-game)

load
 (load-game)

help
 (show-help)


===THINGS===

---cactus---
get
  "Ouch!"

---door---
open 
  (if (have-thing? key)
      (begin
        (set-thing-state! door 'open)
        "The door is now unlocked and open.")
      "The door is locked.")

close
  (begin
   (set-thing-state! door #f)
   "The door is now closed.")

knock
  "No one is home."

и т.п.

плюс синтаксическая раскраска для этого DSL в DrRacket.

языковые модули в схеме, еDSL с простым парсером и ридером, практический пример.

обеспечивается проверка структуры модулей: чтобы секции какие надо куда попало было вставить нельзя.

anonymous ()

language-oriented подхода

Меня это ни черта не восторгает. Для науки это хорошо годится, когда надо запутать следы, или для ситуации, когда надо создать vendor-lock.

Это я говорю как автор некоторого количества DSL-ей.

den73 ★★★★★ ()
Ответ на: комментарий от den73

Для науки это хорошо годится, когда надо запутать следы

может, нужен метаязык типа Literate Programming WEB или Emacs org-mode babel чтобы «распутать следы» ?

для ситуации, когда надо создать vendor-lock.

по-моему, это работает в обе стороны,т.е. чтобы отвязать тоже.

DSL-ей.

каких, если не секрет? кроме ЖЦ БД в SQL

anonymous ()
Ответ на: комментарий от den73

language-oriented подхода

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

так что, не понимаю зачем этого подхода бояться.

программисты привыкли работать с кодом напрямую, а не с некоторым метаязыком поверх него. в итоге они зачастую порождают эти «запутанные следы» в коде, и недоизобретают велосипед вроде Literate Programming WEB.

единственно, чего не хватает этому подходу, IMHO — это обратимости в другую сторону (реверсинга в интегрирующий метаязык из частичного языка DSL), чего-то обратного tangle «untangle».

какого-то гипертекста поверх WEB Literate Programming Дональда Кнута.

хотя для WEB что-то такое было на тему untangle.

лисп это скорее строительный материал или «алгебра программ» или метаязык, по определению более структурированный — чем готовая крупно-блочная компонента.

anonymous ()
Ответ на: комментарий от anonymous

Если бы ты зарегистрировался, мне не пришлось бы называть тебя «тот анонимус, который пропагандирует Literate programming», а ты смог бы узнать, когда кто-то отвечает на твой вопрос.

каких, если не секрет? кроме ЖЦ БД в SQL

Преобразование s-exp в исходники на разных ЯП. Проблема в том, что код хорошо поддерживается инструментами, например, пошаговым отладчиком или сообщениями об ошибках компиляции. Как только ты пишешь свой DSL, на тебя падает работа по поддержке. Если она не сделана хорошо, то тебя проклянут пользователи твоего DSL (в т.ч. ты сам себя проклянёшь). Я вывел язык преобразования s-exp из эксплуатации в большинстве кода именно по той причине, что замучался находить причины ошибок синтаксиса, которые выдавал мне SQL. А до этого некоторое время пытался генерировать хранимые процедуры из s-выражений и даже какое-то количество сгенерировал.

den73 ★★★★★ ()
Ответ на: комментарий от den73

Преобразование s-exp в исходники на разных ЯП.

По-этому надо преобразовывать lang -> lisp, а не lisp -> lang. Такой проблемы не будет.

anonymous ()
Ответ на: комментарий от anonymous

По-этому надо преобразовывать lang -> lisp

Угу. А ты посмотри на все эти многочисленные синтаксисы для sql, javascript на s-выражениях. Единственная годнота здесь - это язык регэкспов в :cl-ppcre, которая в 100 раз лучше собственно регэкспов.

den73 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.