Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[25]

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

functor SymbolFunO : SYMBOL = struct

datatype symbol = symbol of string * ... fun mksymbol(s) = symbol(s,...) fun eqsymbol(syml,sym2) = ... end;

functor AbstSyntaxFun( Symbol: SYMBOL ): ABSTSYNTAX = struct

structure Symbol: SYMBOL = Symbol datatype term =... fun idname(term) = ... end;

functor SymbolTableFun( Symbol : SYMBOL ): SYMBOLTABLE = struct

structure Symbol: SYMBOL = Symbol type entry = ... type table = ... fun mktable() = ... fun lookup(sym,table) = ... end;

signature PARSER PIECES = sig

structure SymbolTable : SYMBOLTABLE structure AbstSyntax : ABSTSYNTAX end;

functor ParserFun( Pieces : PARSER PIECES ): PARSER = struct

structure AbstSyntax : ABSTSYNTAX = Pieces.AbstSyntax structure SymbolTable : SYMBOLTALBLE = Pieces.SymbolTable val symtable = SymbolTable.mktable(); fun parse(str) =

... SymbolTable.lookup( AbstSyntax.idname(t), symtable )... end;

Сигнатура PARSER PIECES содержит две компоненты, от которых зависит синтаксический анализатор, - таблицу символов и дерево синтаксического разбора. Функтор ParserFun использует эту пару для построения


синтаксического анализатора. Функтор SymbolFun не имеет аргументов, поскольку он не зависит ни от чего.

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

structure Symbol: SYMBOL = SymbolFunO; structure Pieces: PARCER PIECES = struct

structure SymbolTable: SYMBOLTABLE = SymbolTableFun(Symbol) structure AbstSyntax: ABSTSYNTAX = AbstSyntaxFun(Symbol) end;

structure Parser: PARSER = ParserFun( Pieces );

Однако мы умолчали о проблеме с ParserFun. Напомним, что функция parse, определенная в Parser, является корректной с точки зрения согласованности типов только потому, что структуры SymbolTable и AbstSyntax включают одну и ту же подструктуру Symbol, и благодаря этому используют один и тот же тип символов. Но теперь в ParserFun функция parse знает только сигнатуры этих двух структур, и ничего не знает о том, как они реализованы. Поэтому ML-компилятор укажет на ошибку в ParserFun, - и наша идея использования функторов для обеспечения модульного стиля программирования оказывается под угрозой.

Спасти дело помогают спецификации соиспользования. Идея состоит в том, чтобы включить в сигнатуру PARSER PIECES набор равенств, гарантирующих тот факт, что только пара совместимых вариантов структур (для работы с таблицей символов и для работы с деревом синтаксического разбора) может быть передана функтору ParserFun. Новый вариант сигнатуры PARSER PIECES будет выглядеть следующим образом:

signature PARSER PIECES = sig

structure SymboiTable : SYMBOLTABLE structure AbstSyntax: ABSTSYNTAX sharing SymbolTable.Symbol = AbstSyntax.Symbol end;

Фраза sharing гарантирует то, что может быть использована только совместимая пара структур SymboiTable и AbstSyntax (где "совместимая" означает "использующая одну и ту же структуру Symbol"). Если теперь мы используем эту модифицированную сигнатуру, то объявление функтора ParserFun становится допустимым.

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


что обе компоненты параметра используют равные подструктуры. Две структуры равны тогда и только тогда, когда они получены в результате вычисления одного того же объявления структуры или применения одного и того же функтора к равным аргументам. Например, следующая попытка сформировать аргументы для функтора ParserFun будет отвергнута, поскольку она не удовлетворяет спецификации sharing:

structure Pieces : PARSER PIECES = struct

structure SymboiTable = SymbolTableFun( SymbolFunO ) structure AbstSyntax = AbstSyntaxFun( SymbolFunO ) end;

Причина здесь в том, что каждое применение SymbolFun создает новую структуру, отличную от всех других.

Другая форма спецификации соиспользования имеет дело с типами. Например, следующая версия PARSER PIECES будет вполне подходящей, если единственное, в чем должны совпадать структуры SymboiTable и AbstSyntax - это используемый ими тип symbol:

signature PARSER PIECES = sig

structure SymboiTable : SYMBOLTABLE structure AbstSyntax : ABSTSYNTAX

sharing SymboiTable.Symbol.symbol=AbstSyntax.Symbol.symbol end;

Равенство типов подобно равенству структур: два типа равны, если они получены в результате вычисления одного и того же объявления. Так, например, если два типа заданы идентичными объявлениями datatype, они будут различными.

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



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32]