Fasulye Makinesi Retrospektif, bölüm 9

Fasulye Makinesi Retrospektif, bölüm 9


C#, F#, Scala ve benzerlerinden farklı olarak yerleşik herhangi bir kalıp eşleştirmesi olmayan bir dil olan Python’da kısa “örüntü eşleştirme” uygulamak istedim. Mantıksal olarak bir kalıp sadece bir yüklemdir: bir değer alan ve değer kalıpla “eşleşiyorsa” true, aksi takdirde false değerini döndüren bir işlev. Bu bölümün kodu burada.

Bu işe başladığımda iki şeyin farkına vardım. Birincisi, hata ayıklama amacıyla, dönüş değerinde yalnızca “doğru” veya “yanlış”tan daha fazla bilgiye sahip olmak güzel olabilir; özellikle karmaşık bir model eşleşmeyi başaramadığında ancak eşleşmesi gerekiyorsa, o zaman bir hata yapmışım demektir. Bu hatayı gidermek için aslında kalıpların yeni bir tür döndürmesini sağladım:

class MatchResult(ABC):
    test: Any
    submatches: Dict[str, "MatchResult")
    # ... and so on, boilerplate code for the rest of this.

Karmaşık bir model, bileşen modellerinin eşleşmemesi nedeniyle başarısız olabilir ve böylece hata sonucuna bilgi dahil edilir. Ayrıca alt sınıflar da yaptım Success Ve Fail.

Biliyor musun, tam da bu anda burada “Başarısız” kelimesini isim olarak kullandığımı fark ettim. Öyle olmalıydı Failure. Oh iyi.

İkincisi, her şey için fonksiyonları kullanmanın kesinlikten yoksun olacağını fark ettim. Baştan sona böyle bir kod yazmak istemedim:

is_binop = lambda x: Success(x) if isinstance(x, ast.BinOp) else Fail(x)

“Bu şey bir binop mu?” kavramı zaten tamamen BinOp tipi tarafından yakalanıyor; Bu nesneyi bir kalıbın gerekli olduğu yerde kullanabilir miyiz?

Farklı seçeneklerle uğraştıktan sonra sonunda şu tür disipline ulaştım:

class PatternBase(ABC):
    @abstractmethod
    def match(self, test: Any) -> MatchResult:
        pass
    def __call__(self, test: Any) -> MatchResult:
        return self.match(test)

Pattern = Union[PatternBase, int, str, float, type, list, None)

Bir model temel nesnesi, bir test değeri alan ve ayrıca çağırabileceğiniz bir işlev olarak değerlendirilebilecek bir eşleşme yüklemine sahiptir.

Bir kalıba ihtiyaç duyduğumuz her yerde, arayan kişi şunları sağlayabilir:

  • desen tabanının bir örneği
  • Hiçbiri, tamsayı, kayan nokta veya dize değeri; anlambilim “test verilen değere eşitse model eşleşir” şeklindedir.
  • bir tür; anlambilim “testin verilen türde olması durumunda model eşleşir”
  • kalıpların bir listesi; anlambilim şu şekildedir: “test aynı uzunlukta bir liste ise ve her liste öğesi karşılık gelen kalıpla eşleşiyorsa kalıp eşleşir”

Buraya kadar şu kalıpları ifade edebiliriz:

p = [ BinOp, 3, None ) 
# p matches a list of three items where the first is a binary op AST,
# the second is the number 3, and the third is the value None

Ancak “eşleşme örneklerini” nasıl ifade edebiliriz? Foo kimin bar özellik 3″ mü? Birden fazla kalıpla nasıl eşleşiriz sorusuna ilişkin daha genel bir sorunu çözerek başlayabiliriz. İşte ilk birleştiricimiz:

def match_every(*patterns: Pattern) -> Pattern:
  # ... the implementation is tedious to make it efficient,
  # but you get the idea; we produce a pattern which succeeds if
  # every given subpattern succeeds, and fails otherwise.

Test edilen değerin bir özelliği olan bir alt modelin eşleştirilmesine ilişkin spesifik problemi çözebiliriz:

class AttributeSubpattern(PatternBase):
    name: str
    subpattern: Pattern
    def match(self, test: Any) -> MatchResult:
        submatch = match(self.subpattern, getattr(test, self.name, None))
        submatches = {self.name: submatch}
        if submatch.is_success():
            return Success(test, submatches)
        return Fail(test, submatches)
    # ...

Aramak biraz hantal AttributeSubpattern bu yüzden bir eşanlamlı işlevi yaptım attribute ilave olarak. Bu sınıfın bir birleştirici olduğuna dikkat edin; bir modeli alır ve yeni bir model üretir.

Ve şimdi ilk ikisinden üçüncü bir birleştirici yapabiliriz: Bir nesnenin belirli bir türde olup olmadığını ve bir modelle eşleşen bir özniteliğe sahip olup olmadığını kontrol eden bir model istiyorum:

def type_and_attributes(typ: type, patterns: Dict[str, Pattern)) -> Pattern:
    t: List[Pattern) = [typ)
    tuples: List[Pattern) = [
        attribute(name, subpattern) for (name, subpattern) in patterns.items()
    )
    return match_every(*(t + tuples))

Ve şimdi söyleyebiliriz

is_addition = type_and_attributes(BinOp, {"op": Add})

Veya daha da iyisi, her zaman eşleşen bir model ve başka bir birleştirici oluşturalım:

class AnyPattern(PatternBase):
    def match(self, test: Any) -> MatchResult:
        return Success(test)

_any = AnyPattern()

def binop(
  op: Pattern = _any, 
  left: Pattern = _any, 
  right: Pattern = _any) -> Pattern:
  return type_and_attributes(
    BinOp, {"op": op, "left": left, "right": right})

is_addition = binop(Add)

Ayrıca aşağıdakiler için kalıpları veya birleştiricileri tanımladım:

  • Bu kalıplardan en az biriyle eşleşin
  • Listedeki ilk öğeyi bir kalıpla ve listenin sonunu başka bir modelle eşleştirin
  • Listedeki en az bir öğeyi belirli bir kalıpla eşleştirin
  • Listedeki tüm öğeleri aynı kalıpla eşleştirin
  • Bu desenin tersini eşleştirin
  • Tanımlayıcılar, işleçler vb. gibi yaygın olarak kullanılan AST düğümleri için yardımcı birleştiriciler.
  • Ve benzeri; Fikri anladın.

Araç kutumdaki bu araçlarla, “bu listedeki herhangi bir öğe tanımlayıcı değil mi?” gibi kalıpları hızla oluşturabiliyordum.

any_non_id = ListAny(negate(name()))

Desenler hangi kodun dönüştürülmesi gerektiğini tanımlar; kurallar onları dönüştürür. FAIC’de bir dahaki sefere AST dönüşümlerini kısaca temsil etmek için bir dizi kural ve kural birleştiricileri oluşturmaya bakacağız.



Source link

Postagens Similares

  • Por que é impossível concordar sobre o que é permitido

    Em grandes plataformas, é impossível ter políticas sobre questões como moderação, spam, fraude e conteúdo sexual com as quais as pessoas concordem. David Turner fez um jogo simples para ilustrar como isso é difícil, mesmo em um caso trivial, No Vehicles in the Park. Se você ainda não jogou, recomendo jogar agora antes de continuar…

  • Dustin Mierau

    Un sitio web para mis pensamientos, fotografías, biblioteca, arte y trabajo.Navega alrededor. Deja una marca. Programas Blog Reloj Globo Biblioteca Fotos Cartera Rompecabezas Rolodex Sellos Hablar Terminal TELEVISOR Blog Hola, me he creado un sitio web. Fotos Biblioteca Arco — Ugo Bienvenu En arco iris – Radiohead Recuerdos de acceso aleatorio – Daft Punk Accidente…

  • جیسکا لیونگسٹن

    نومبر 2015 کچھ مہینے پہلے Y Combinator کے بارے میں ایک مضمون میں کہا گیا تھا کہ اس کا آغاز ایک “ون مین شو” تھا۔ اس طرح کی چیز پڑھنا افسوسناک طور پر عام ہے۔ لیکن اس وضاحت کے ساتھ مسئلہ صرف یہ نہیں ہے کہ یہ غیر منصفانہ ہے۔ یہ بھی گمراہ کن ہے۔…

  • Andika kwa Urahisi

    Machi 2021 Ninajaribu kuandika kwa kutumia maneno ya kawaida na sentensi rahisi. Aina hiyo ya uandishi ni rahisi kusoma, na kadiri kitu kinavyokuwa rahisi kusoma, ndivyo wasomaji wanavyojihusisha nacho kwa undani zaidi. Kadiri wanavyotumia nguvu kidogo kwenye nathari yako, ndivyo watakavyokuwa wamesalia kwa mawazo yako. Na zaidi watasoma. Nishati ya wasomaji wengi huelekea kuripoti kwa…

  • Poza mądrością

    Październik 2021 Gdybyś zapytał ludzi, co jest specjalnego w Einsteinie, większość odpowiedziałaby, że był naprawdę mądry. Nawet ci, którzy próbowali udzielić Ci bardziej wyrafinowanej odpowiedzi, prawdopodobnie pomyśleliby o tym jako pierwsi. Jeszcze kilka lat temu sam udzieliłbym tej samej odpowiedzi. Ale nie to było wyjątkowe w Einsteinie. To, co go wyróżniało, to to, że miał…

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *