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

  • 雙子座3.1 Flash TTS

    2026 年 4 月 15 日 – 連結博客 雙子座3.1 Flash TTS。 Google 今天發布了 Gemini 3.1 Flash TTS,這是一種可以使用提示進行定向的新文字轉語音模型。 它透過標準 Gemini API 使用 gemini-3.1-flash-tts-preview 作為型號ID,但只能輸出音訊檔案。 至少可以說,提示指南令人驚訝。這是他們產生幾個簡短的音訊句子的範例提示: # AUDIO PROFILE: Jaz R. ## “The Morning Hype” ## THE SCENE: The London Studio It is 10:00 PM in a glass-walled studio overlooking the moonlit London skyline, but inside, it…

  • Kwa Nini Ni Salama Kwa Waanzilishi Kuwa Wazuri

    Agosti 2015 Hivi majuzi nilipata barua pepe kutoka kwa mwanzilishi ambayo ilinisaidia kuelewa jambo muhimu: kwa nini ni salama kwa waanzilishi wa kuanzisha kuwa watu wazuri. Nilikua na wazo la katuni la mfanyabiashara aliyefanikiwa sana (katika katuni siku zote alikuwa mwanamume): mtu mkali, mvutaji sigara, mpiga meza mwenye umri wa miaka hamsini ambaye anashinda kwa…

  • Erin | Greg Ladin’in Blogu

    Bir dakika oldu. Atlantik Kasırga Havzasında pek fazla ilgi görmeden “E” harfine kadar geldik ama artık elimizde Erin var. Erin tropik bir fırtınadır ancak bir kasırgaya ve muhtemelen büyük bir kasırgaya dönüşmesi beklenmektedir. Bunu kesin olarak söylemek için henüz çok erken, ancak mot modellerinde Erin rüzgar altı ve rüzgar üstü adaların kuzeyine doğru yöneliyor, sonra…

  • दशलक्ष वि. अब्ज वि. ट्रिलियन

    आम्ही दशलक्ष, अब्ज आणि ट्रिलियन हे शब्द ऐकतो. आणि आम्हाला माहित आहे की दहा लाख आहेत, एक अब्ज संपूर्ण आहे आणि ट्रिलियन त्यापेक्षाही अधिक आहे. परंतु प्रत्यक्षात फरक किती मोठा आहे हे पाहण्याचा एक चांगला मार्ग येथे आहे. दहा लाख सेकंद किती काळ आहे? प्रथम, मला एक प्रश्न विचारू द्या: एक दशलक्ष सेकंद किती काळ…

Deixe um comentário

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