[PYTHON] Mit algebraischen Datentypen und objektorientierter Programmierung

Der Titel ist unklar.

Es gibt einen Aufsatz über funktionale Programmierung (Sprache).

Ich habe es gelesen, weil es einen großartigen übersetzten Artikel gibt.

[Algebraischer Datentyp] in OCaml in diesem Aufsatz ausgedrückt (http://ja.wikipedia.org/wiki/%E4%BB%A3%E6%95%B0%E7%9A%84%E3% 83% 87% E3% 83% BC% E3% 82% BF% E5% 9E% 8B) und Beispiele für Mustervergleich werden vorgestellt.

  • Ausdruck und Evaluator in OCaml
type 'a expr = | True 
               | False 
               | And  of  'a expr * 'a  expr 
               | Or   of  'a expr * 'a  expr 
               | Not  of  'a expr 
               | Base of  'a  
 
let  rec eval eval_base expr  = 
   let  eval' x = eval eval_base x in 
   match expr with 
   | True  -> true 
   | False -> false 
   | Base base  -> eval_base base 
   | And  (x,y) -> eval' x && eval' y  
   | Or  (x,y)  -> eval' x || eval' y 
   | Not  x     -> not (eval' x) 

Es bietet auch einen Vergleich dessen, was passiert, wenn das Äquivalent in Java implementiert wird. Ich denke, dass viele nicht funktionierende Programmiersprachen keine algebraischen Datentypen (direkte Summentypen) als Sprachen unterstützen. Python ist eine solche Sprache. Ersetzen Sie den im Artikel eingeführten Java-Code durch Python.

Erstens ist die Implementierung des Evaluators. Da der Java-Code im Originalartikel nur die Schnittstelle definiert und die Implementierung nicht einführt, verwenden wir auch * ABCMeta * und * abstractmethod * für die Schnittstelle, und die Implementierung ist angemessen.

3.4


from abc import ABCMeta, abstractmethod

class Evaluator(metaclass=ABCMeta):
    @abstractmethod
    def evaluate(self, value): pass

class MyEvaluator(Evaluator):
    def evaluate(self, value):
        return bool(value)

Fahren wir nun mit der Definition von Booleschen Ausdrücken und den Funktionen fort, die sie auswerten. Wie der * Evaluator * oben erbt er ein schnittstellenähnliches Objekt namens * Expr * und definiert jeden Ausdruck als Objekt.

3.4


class Expr(metaclass=ABCMeta):
    @abstractmethod
    def eval(self, evaluator): pass

class True_(Expr):
    def eval(self, evaluator):
        return True

class False_(Expr):
    def eval(self, evaluator):
        return False

class Base(Expr):
    def __init__(self, value):
        self.value = value

    def eval(self, evaluator):
        return evaluator.evaluate(self.value)

class And(Expr):
    def __init__(self, expr1, expr2):
        self.expr1 = expr1
        self.expr2 = expr2

    def eval(self, evaluator):
        return self.expr1.eval(evaluator) and self.expr2.eval(evaluator)

class Or(Expr):
    def __init__(self, expr1, expr2):
        self.expr1 = expr1
        self.expr2 = expr2

    def eval(self, evaluator):
        return self.expr1.eval(evaluator) or self.expr2.eval(evaluator)

class Not(Expr):
    def __init__(self, expr):
        self.expr = expr

    def eval(self, evaluator):
        return not self.expr.eval(evaluator)

Ist es so

Lassen Sie uns die Details beiseite legen und ausführen, um zu sehen, ob es funktioniert.

3.4


>>> from sample1 import *
>>> evaluator = MyEvaluator()
>>> true, false = True_(), False_()
>>> true.eval(evaluator)
True
>>> And(Base(3), false).eval(evaluator)
False

Ich habe das Gefühl, dass das Aufrufen wie eine * eval * -Funktion eher so aussieht.

3.4


>>> from operator import methodcaller
>>> eval_ = methodcaller('eval', evaluator)
>>> eval_(Not(true))
False
>>> eval_(Or(And(Base(3), false), Not(false)))
True

・ ・ ・

Es ist wahrscheinlich nicht sehr wichtig (ich mache es nur, um die Implementierung zu testen).

Ich konnte die direkte Summe der algebraischen Datentypen mithilfe von Schnittstellen (wie Dingen) und Vererbung ausdrücken. Schauen wir uns nun die Definition algebraischer Datentypen in Ocaml an.

type 'a expr = | True 
               | False 
               | And  of  'a expr * 'a  expr 
               | Or   of  'a expr * 'a  expr 
               | Not  of  'a expr 
               | Base of  'a  

Originaler Artikel(Übersetzung)Zitiert aus

Der direkte Summentypausdruck wird durch eine Pipe angezeigt, die die verschiedenen Deklarationsteile trennt. Von diesen Deklarationen sind beispielsweise True und False einzelne Tags und praktisch identisch mit Java- und C-Aufzählungselementen. Andere, wie And and Not, haben Daten gebunden, die sich von Zeit zu Zeit ändern können. Dieser Typ enthält tatsächlich sowohl den direkten Summentyp als auch den direkten Produkttyp, da die Teile And und Or Taples enthalten. Ein Typ, der aus einer Kombination von Produkt- und Summen-Mehrfachstrukturen besteht, ist in OCaml üblich und eine mächtige Redewendung.

Anstatt es in einer Klasse mit Vererbung auszudrücken**|** (Rohr)Es ist unbestritten, dass der in beschriebene Ausdruck viel prägnanter ist.

Darüber hinaus ist der direkte Summentyp ein Aufzählungstyp(enum)Aber es wird gesagt, dass es ausgedrückt werden kann, also versuchen wir es auch. Python 3.Von 4 bis zur StandardbibliothekenumModule wurden hinzugefügt. StandardenumWeil es nicht präzise ausgedrückt werden kannextenumIch benutze die Erweiterung, aber keine Sorge, es ist nicht wesentlich.

3.4


from extenum import ConstantSpecificEnum

class Expr(ConstantSpecificEnum):

    TRUE = 1
    FALSE = 2
    BASE = 3
    AND = 4
    OR = 5
    NOT = 6

    @overload(TRUE)
    def eval(self, evaluator, *args):
        return True

    @overload(FALSE)
    def eval(self, evaluator, *args):
        return False

    @overload(BASE)
    def eval(self, evaluator, *args):
        return evaluator.evaluate(args[0])

    @overload(AND)
    def eval(self, evaluator, *args):
        return evaluator.evaluate(args[0]) and evaluator.evaluate(args[1])

    @overload(OR)
    def eval(self, evaluator, *args):
        return evaluator.evaluate(args[0]) or evaluator.evaluate(args[1])

    @overload(NOT)
    def eval(self, evaluator, *args):
        return not evaluator.evaluate(args[0])

EinerenumDa wir ein Objekt definieren konnten, das einem Ausdruck in der Klasse entspricht, ist es möglicherweise etwas besser als das vorherige Vererbungsbeispiel.

3.4


>>> from sample2 import *
>>> Expr.TRUE.eval(evaluator)
True
>>> Expr.AND.eval(evaluator,
...               Expr.BASE.eval(evaluator, 3),
...               Expr.FALSE.eval(evaluator))
...
False

Wenn Sie den Evaluator ausblenden, weil er redundant aussieht,

3.4


>>> true = Expr.TRUE.eval(evaluator)
>>> false = Expr.FALSE.eval(evaluator)

>>> from functools import partial
>>> Base = partial(Expr.BASE.eval, evaluator)
>>> And = partial(Expr.AND.eval, evaluator)
>>> Or = partial(Expr.OR.eval, evaluator)
>>> Not = partial(Expr.NOT.eval, evaluator)

>>> Not(true)
False
>>> Or(And(Base(3), false), Not(false))
True

Es wurde einfacher, so zu sehen(Es ist einfacher zu testen, ob es funktioniert) 。

In Hatebs Kommentar gab es einen Kommentar, dass es nicht fair ist, die Merkmale der funktionalen Programmiersprache auszudrücken und der prozeduralen Programmiersprache gegenüberzustellen. Ich denke, es macht Sinn, aber ich lobe einen im Gegensatz dazu.(Verachten)Ich fand den Originalartikel vielmehr wunderbar, um darüber nachzudenken, wie verschiedene Programmiersprachenparadigmen für denselben Zweck verwendet werden.

Zum Beispiel bin ich mit funktionalen Programmiersprachen nicht vertraut, daher ist es immer noch einfacher zu verstehen, was der Code in Java vorhat als in OCaml. Und aus dem gleichen Grund habe ich es in Python geschrieben.

Wenn der Ausdruck kurz ist, ist es besser und programmierbar(Sprache)Ich dachte, es wäre ein gutes Beispiel, um zu erkennen, dass das Paradigma und die Ausdruckskraft des Codes eng miteinander verbunden sind.

Recommended Posts

Mit algebraischen Datentypen und objektorientierter Programmierung
Mit algebraischen Datentypen und FizzBuzz
Mit algebraischen Datentypen und Mustervergleich
Verständnis der Datentypen und des Beginns der linearen Regression
Was ist "funktionale Programmierung" und "objektorientiert"? Python Edition
Airflow-I hat versucht, den Zeitplan zu programmieren und die Datenpipeline zu überwachen
cv2-Funktionen und Datentypen (OpenCV-Python-Bindung)
Programmieren mit Python und Tkinter
Koordinator und ganzzahliger linearer Plan
Punkt- und Figurendatenmodellierung
CSV-Daten extrahieren und berechnen
Empfohlene Bücher und Quellen für die Datenanalyseprogrammierung (Python oder R)