これは、「遅延モダリティを使用して固定点演算子から (無限) ツリーを計算する」のバリエーションです。
設定。ルートからのパスによってツリー内の任意の他のノードを参照する機能が追加されたバイナリ ツリーの言語を研究します。
type Path = [Bool]
data STree = SNode STree STree
| SPath Path
| SLeaf Int
deriving (Show)
パスは何らかのルートのコンテキストで定義され、パスに False/True が表示されると、左/右の子を連続してたどって見つかったサブツリーを識別します。たとえば、パスはツリーで[False, True]
識別されます。SLeaf 2
SNode (SNode (SLeaf 1) (SLeaf 2)) (SLeaf 3)
このようなツリーは、たとえば、任意のフロー グラフを識別するために使用できます (既約グラフを含み、固定小数点演算子を使用することはできません)。
この記述によって導かれる無限木を考えることができます。
data Tree = Node Tree Tree
| Leaf Int
deriving (Show)
follow
以下は、ツリーのあるパスでサブツリーを見つける補助関数を利用した、一方から他方への変換関数です。
follow :: Path -> Tree -> Tree
follow [] s = s
follow (False : p) (Node s _) = follow p s
follow (True : p) (Node _ s) = follow p s
follow _ (Leaf _) = error "bad path"
flatten' :: Tree -> STree -> Tree
flatten' root (SPath p) = follow p root
flatten' root (SNode s1 s2) =
Node (flatten' root s1) (flatten' root s2)
flatten' _ (SLeaf i) = Leaf i
flatten :: STree -> Tree
flatten s = fix (\root -> flatten' root s)
残念ながら、この関数は生産的ではありません: で無限ループしflatten (SPath [])
ます。
問題。ここで、遅延モダリティ ( 「遅延モダリティを使用して固定点演算子から (無限) ツリーを計算する」で説明されているように) で拡張されたこの構造の変形と、Loop
自己参照ループを示すコンストラクターを検討します。
data Tree = Node (D Tree) (D Tree)
| Leaf Int
| Loop
deriving (Show)
非構造的に再帰的な関数呼び出しを使用せずに (構造的にSTree
and を再帰することができます)、無限ツリーを展開Path
する関数STree -> Tree
(または同様のもの) を記述します。
追記。多くの場合、無限の展開を計算したくありません。存在する場合は有限の展開が必要であり、そうでない場合はエラーが必要です。具体的には、元のデータ型が与えられた場合:
data Tree = Node Tree Tree
| Leaf Int
deriving (Show)
非構造的再帰を使用せずにSTree -> Maybe Tree
、構文を有限ツリーに展開する関数 (または同様の関数) を記述したいと思うかもしれません。この構造に遅延モダリティがないため、有限であることが保証されます。
この構造には遅延モダリティのインスタンスがないため、 でこれを行うことは不可能に思われfixD
ます。決して使用できない遅延結果が得られます。ツリーをグラフに変換し、それをトポロジカルにソートしてから、 を使用せずにガウス消去法のアルゴリズムを直接実装する必要があるように思われますfixD
。
元の (間違った) コードと同じくらいエレガントに展開を実装できる別の型付け規則はありますか? もしそうなら、グラフのサイクルを見つけるための別のアルゴリズムを (再) 発見しただけかもしれません。