Hacker News new | past | comments | ask | show | jobs | submit login

Can anyone give a Tl;DR about how this works? Don't x and y need to exist beforehand?



It's hard to give a TL;DR on the whole library, but case classes can be used with for example pattern matching (https://github.com/lihaoyi/macropy#pattern-matching).

The following code:

  with patterns:
      Foo(x, Bar(3, z)) << Foo(4, Bar(3, 8))
The constructor after the << will be matched with the part before <<. It will only match if the first argument of "Bar" is 3. If that's the case, x and z will be bound to 4 and 8.

Does this help? :)


I'm sure there's a use-case for this, but I'm not coming up with one off the top of my head. This comes across as an extremely rare type of problem to encounter.

What's the purpose of only binding x and z if the first argument of Bar matches? What if it doesn't match? Is an exception thrown? Are x,z just None?

[Note: I'm talking about the example, not the @case decorator, which does seem useful]

Edit:

After reading the library examples, the explanation above is not entirely clear:

  with patterns:
      Foo(x, Bar(3, z)) << Foo(4, Bar(3, 8))
here's the rest of the example:

    print x   # 4
    print z   # 8
I was thinking that somehow a new Foo instance was created only when the pattern matched. (Oh, and an exception is thrown when the match fails)


Author here. The `<<` operator is being abused to mean "bind", so the right side is a normal expression (constructing a Foo and Bar) and the left side matches it to a particular "shape".

The purposes of pattern matching is to replace code that looks like this:

    if  (isinstance(tree, BinOp)
            and type(tree.left) is Name
            and type(tree.op) is Mod
            and tree.left.id in module.expr_registry):
        ...
with code that looks like this

    if BinOp(Name(id), Mod(), body) << tree 
            and id in module.expr_registry:
        ...
Which looks much nicer, and more clearly says what you want: that `tree` "looks like" a particular shape.

EDIT: Here's another example. Turning this:

    if  ((isinstance(tree, ClassDef) or isinstance(tree, FunctionDef))
            and len(tree.decorator_list) == 1
            and tree.decorator_list[0]
            and type(tree.decorator_list[0]) is Name
            and tree.decorator_list[0].id in module.decorator_registry):
        ...
into:

    if  ((isinstance(tree, ClassDef) or isinstance(tree, FunctionDef))
            and [Name(id)] << tree.decorator_list 
            and id in module.decorator_registry):
        ...
Doesn't quite work yet, but we're getting there


Personally, I find those to be better 'real world' examples. I would suggest including them in the docs. Thanks for the explanation!


With pattern matching, the term on the left is a destructuring of the term on the right. Using a static instance like that isn't what you normally do in practice, but rather something like:

    myfoo = Foo(4, Bar(3, 8))
    with patterns:
        Foo(x, Bar(3, z)) << myfoo
        
So in this case, the assertion will only pass if the Foo contains a Bar in the second slot, and that Bar contains a 3 in its first slot, while also binding the 4 and 8 to their own names, x and z respectively.


That's known as destructuring-bind: http://www.lispworks.com/documentation/HyperSpec/Body/m_dest...

Is that a macro created by this library or a feature of the library?

Edit: I did some reading and it looks to be a feature macro of the library.


From the opening paragraph of the readme.md

> MacroPy provides a mechanism for user-defined functions (macros) to perform transformations on the abstract syntax tree(AST) of Python code at module import time

Basically it rewrites the code before it's compiled, so no, x and y don't need to exist (compilation hasn't finished when the macro runs)


Decorators can do this? I did not know this. I thought decorators just get handed the object after initialization, so something like:

    @blah
    class Lol:
      pass
is equivalent to:

    class Lol:
      pass
    blah(Lol)
What am I missing?


> What am I missing?

Import hooks.


Should've RTFM'ed. Thanks :)


isn't it equivalent to

  class Lol:
    pass
  Lol = blah(Lol)


Sorry, yes.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: