Pythonの再帰データ型

Sep 02 2020

Haskellの再帰データ型に最も近いPythonのことは何でしょうか?(つまり、タイプ自体を定義するときに、タイプ自体の定義を使用します。)

編集:

再帰型のより具体的な定義を与えるために、以下はHaskellの二分木です。

data Tree a             = Leaf a | Branch (Tree a) (Tree a) 

私がこれを読む方法は次のようです:二分木は葉であるか、またはタイプツリー自体である2つのサブツリーを含むことができます。

Haskellの再帰型の詳細については、以下を参照してください。 https://www.haskell.org/tutorial/goodies.html

私が実際に考えていたのは、Haskellの単語ツリー定義をPythonに変換することでした。これはWordTree私の古いプロジェクトからの定義です:

data WordTree = Word String | Subword String [WordTree] | Root [WordTree]

AWordTreeは、単語の一般的な接頭辞が親に格納され、残りの部分がソートされた方法でツリーの葉に格納されるn-arytree構造です。この型の定義はTrieにいくぶん似ていると思います。それでも、Haskellは関数型プログラミング言語であるため、この型定義を再帰的にすることができます。この種の型の定義に最も近いのは、Python(または一般的にはオブジェクト指向プログラミング)では何でしょうか?

回答

3 Elazar Sep 02 2020 at 03:19

Pythonは動的に型指定されるため、必要なクラスを定義するのに問題はありません。

class Tree:
    left = None
    right = None
    def __init__(self, left, right):
        self.left = left
        self.right = right

これらの定義の入力に興味がある場合でも、他のクラスベースのオブジェクト指向言語と同じように入力できます。

from typing import Union

class Tree:
    left: Union['Tree', int]
    right: Union['Tree', int]
    def __init__(self, left: Union['Tree', int], right: Union['Tree', int]) -> None:
        self.left = left
        self.right = right

タイプの名前に文字列が使用されていることに注意してください(最近のPythonバージョンでは回避できます)。

次のような直接再帰代数型については、mypyのこの未解決の問題を参照してください。

Tree = Union[Tuple['Tree', 'Tree'], int]

WordTree説明する定義の最も一般的な(必ずしも推奨されるわけではありませんが)方法は、スーパークラスと浅い階層を使用することです。

from typing import List, final

class WordTree: pass

@final
class Word(WordTree):
    word: str

@final
class Subword(WordTree):
    subword: str
    children: List[WordTree]

@final
class Root(WordTree):
    children: List[WordTree]

このような実装を使用すると、使用して必要な場合がありますisinstance(Python3.9があなたに与えてもチェックが素敵な砂糖それらのために)。この例では、混乱を避けるためにコンストラクターは省略されています。dataclassそれらや他の種類の動作を簡単に取得するために使用することをお勧めします。

現在まで、Pythonには、無関係のクラスがから継承することを禁止する方法がないWordTreeため、そのようなプログラムについて静的に推論する機能の一部が壊れています。

ScalaやKotlin、(まもなく)Javaなどの他のいくつかのOOP言語は、(sealedクラスを使用して)そのような定義を取り、Haskellなどの関数型言語で提供されるものと同様の型チェックと構文構造を提供できます。


私が知っている限りでは、この種の設計は通常、ASTなどの純粋なデータクラスにのみ推奨されます。データ構造の内部動作を公開するため、trieなどのユーザー向けコンテナの定義にはあまり適していません。したがって、その設計を採用する場合でも、それを実装の詳細として使用し、Trie明確に定義されたAPIを介してクライアントコードで使用される別のクラスを使用することをお勧めします。そのクラスには、WordTreeフィールド、または同じロジックを実装する他の方法を含めることができます。

IMOこれは、オブジェクト指向設計が機能設計とどのように異なるかにとって不可欠です。後者はデータフローと静的推論に焦点を当てていますが、前者はAPI、拡張性、デカップリングに焦点を当てています。言語と環境の間で移植する場合、これは注意するのに役立つと思います-上記のように、一部の言語は両方の設計アプローチを有効にしようとします。