[PYTHON] Mit algebraischen Datentypen und FizzBuzz

Der Titel ist unklar.

[PyAlgebraicDataTypes] Ich habe mit (https://github.com/benanhalt/PyAlgebraicDataTypes) gespielt. Inspiriert von der Sprache Racket [Algebraic Data Types](http://ja.wikipedia.org/wiki/%E4%BB%A3%E6%95 Es scheint sich um eine Bibliothek zu handeln, die% B0% E7% 9A% 84% E3% 83% 87% E3% 83% BC% E3% 82% BF% E5% 9E% 8B) in Python ausdrückt. Ich habe es versucht, weil es klein war und gut zum Lernen aussah.

3.4


>>> from adt import ADT, Require
>>> class List(ADT): pass
... 
>>> class Nil(List): pass
... 
>>> class Cons(List):
...   car = Require(int)
...   cdr = Require(List)

3.4


>>> Nil()
Nil()

Eine Liste mit Elementen

3.4


>>> Cons(1, Cons(2, Nil()))
Cons(car=1, cdr=Cons(car=2, cdr=Nil()))

Es kann ausgedrückt werden, indem * Cons * an * Cons.cdr * übergeben wird. Wenn kein Element vorhanden ist, können Sie das Ende mit * Nil * ausdrücken.

Es ist mühsam, diese * List * -Daten von Hand zu schreiben. Definieren wir also eine * range_ * -Funktion, deren Element durch das Argument angegeben wird.

3.4


>>> def range_(until, value=0):
...     return Nil() if value == until else Cons(value, range_(until, value + 1))
... 
>>> range_(5)
Cons(car=0, cdr=Cons(car=1, cdr=Cons(car=2, cdr=Cons(car=3, cdr=Cons(car=4, cdr=Nil())))))

Ich konnte meinen eigenen * List * -Typ mit einer Listendatenstruktur definieren.

Jetzt, da ich weiß, wie man es benutzt, werde ich * FizzBuzzList * mit einer Datenstruktur wie Fizz Buzz definieren.

3.4


class FizzBuzzList(List):
    pass

class Value(FizzBuzzList):
    value = Require(int)

class Fizz(FizzBuzzList):
    value = Require(int)

class Buzz(FizzBuzzList):
    value = Require(int)

class FizzBuzz(FizzBuzzList):
    value = Require(int)
    fizz = Require(Fizz)
    buzz = Require(Buzz)

3.4


def fbrange(until, value=0):
    """
    >>> fbrange(6, 1)  # doctest: +NORMALIZE_WHITESPACE
    Cons(car=Value(value=1), cdr=Cons(car=Value(value=2),
         cdr=Cons(car=Fizz(value=3), cdr=Cons(car=Value(value=4),
         cdr=Cons(car=Buzz(value=5), cdr=Nil())))))
    """
    def make_cons(obj):
        return Cons(obj, fbrange(until, obj.value + 1))

    if value == until:
        return Nil()
    elif value % 15 == 0:
        return make_cons(FizzBuzz(value, Fizz(value), Buzz(value)))
    elif value % 5 == 0:
        return make_cons(Buzz(value))
    elif value % 3 == 0:
        return make_cons(Fizz(value))
    return make_cons(Value(value))

Wenn Sie sich Fizz Buzz als Datenstruktur vorstellen, wird die Logik beim Erstellen der Daten deutlich. Hier wird es durch die Logik von Fizz Buzz generiert, die allgemein genannt wird, aber Sie können auch mit Ihrer eigenen Logik über die Datenstruktur von Fizz Buzz nachdenken.

[MatchCases] Musterübereinstimmungen können ausgedrückt werden, indem ein erbender Matcher erstellt wird (https://github.com/benanhalt/PyAlgebraicDataTypes#match-cases). Lassen Sie uns Muster mit dieser Datenstruktur abgleichen und Fizz Buzz ausgeben.

3.4


from adt import MatchCases

class FizzBuzzMatch(MatchCases):
    def value(match: Value):
        return value
    def fizz(match: Fizz):
        return 'fizz'
    def buzz(match: Buzz):
        return 'buzz'
    def fizzbuzz(match: FizzBuzz):
        return FizzBuzzMatch(fizz) + FizzBuzzMatch(buzz)
    def cons(match: Cons):
        return '{}, {}'.format(FizzBuzzMatch(car), FizzBuzzMatch(cdr))
    def nil(match: Nil):
        return None

So was.

3.4


>>> FizzBuzzMatch(fbrange(16, 1))
'1, 2, fizz, 4, buzz, fizz, 7, 8, fizz, buzz, 11, fizz, 13, 14, fizzbuzz, None'

Da Python dynamisch typisiert ist, selbst wenn es in einem Mustervergleichsstil geschrieben ist, kann der tatsächliche Fehler nur zur Laufzeit erkannt werden. Selbst wenn es wie unten gezeigt mit * isinstance * implementiert wird, macht es in diesem Beispiel möglicherweise keinen großen Unterschied. ..

3.4


def match_fizzbuzz(fblist):
    if isinstance(fblist, Value):
        return fblist.value
    elif isinstance(fblist, Fizz):
        return 'fizz'
    elif isinstance(fblist, Buzz):
        return 'buzz'
    elif isinstance(fblist, FizzBuzz):
        return match_fizzbuzz(fblist.fizz) + match_fizzbuzz(fblist.buzz)
    elif isinstance(fblist, Cons):
        return '{}, {}'.format(
                match_fizzbuzz(fblist.car),
                match_fizzbuzz(fblist.cdr))
    elif isinstance(fblist, Nil):
        return None

Die if-Anweisung erzeugt jedoch eine Abhängigkeit von der Reihenfolge. Wenn also der Datentyp abgeleitet und kompliziert ist (z. B. wenn der FizzBuzz-Typ den Fizz-Typ und den Buzz-Typ erbt). Ich bin der Meinung, dass die Strenge der Typanpassung effektiv ist.

Python unterstützt keine algebraischen Datentypen (direkte Summentypen) als Sprache

Ich denke nicht, dass es normal ist, darüber nachzudenken, deshalb war es interessant, es zu versuchen und den Unterschied im Denken zu erkennen.

Eine weitere Sache, die Logik von Fizz Buzz, kam heraus, als die Daten generiert wurden. Mir ist aufgefallen, dass es auch anders ist, dass das Ausgabeergebnis geändert werden kann, ohne die Ausgabeseite (bei der Musterübereinstimmung) durch Ändern der Datengenerierungsmethode zu ändern.

Recommended Posts

Mit algebraischen Datentypen und FizzBuzz
Mit algebraischen Datentypen und Mustervergleich
Mit algebraischen Datentypen und objektorientierter Programmierung
Verständnis der Datentypen und des Beginns der linearen Regression
Python-Variablen und Datentypen, die mit Chemoinfomatik gelernt wurden
cv2-Funktionen und Datentypen (OpenCV-Python-Bindung)
FizzBuzz Problem dies und das
CSV-Daten extrahieren und berechnen
Hinweise zu Python- und Wörterbuchtypen
Memo "Kapitel 5 - Wörterbücher und Strukturierung von Daten"
Hashing von Daten in R und Python
Über Zeitreihendaten und Übertraining
Extrahieren Sie Pokemon GO Pokemon-Daten und Skill-Daten