evhub / coconut

Simple, elegant, Pythonic functional programming.
http://coconut-lang.org
Apache License 2.0
4.1k stars 125 forks source link

Add feature for code inlining/macro/rewriting #380

Closed ArneBachmann closed 1 year ago

ArneBachmann commented 6 years ago

I'm having cases where I repetitively write the same code parts (as a replacement for some built-in stuff), and want to simplify. However, I don't want to replace everything by a dedicated function, as it introduces one more call indirection.

What came to my mind then was 1) the ability to have the transpiler insert (or inline) (source) code for me, as concatenative programming languages can. It's probably too much magic for the Pythonic approach, but sounds useful.

There could be a new syntactic element [[ <function reference> ]] which rolls out the function's (or lambda's) code instead of the square bracket section, plus mapping/matching variables from the scope to what the function declares.

This way we would have DRY principle, but avoid calling the function everywhere, as it will be inlined in source form in all places.

Another idea 2) would be to be able to specify code rewriting from the user code, similar to defining macros in C or Apache server rewrite rules. Each occurrence would be automatically replaced by the transpiler. To avoid unexpected effects, again some syntactic element could be introduced to make it explicit ([[ and ]]).

JacobFV commented 1 year ago

I don't see any uses for this syntax pattern: << IDENTIFIER >> (unless someone has defined custom operators for << and >>). Maybe it'd be useful for referencing inline functions?

ArneBachmannDLR commented 1 year ago

Well my idea is almost 5 years old now, I don't even remember the actual use case (only the project I was working on), so it's hard to create an actionable example. It still reads useful, but not concrete enough. If the main idea was something like macros, I'd look like that:

def my_convenience_macro(a:int, b:str, func:Callable[[str],str]) -> None:
  for i in range(a):
    print(func(b))

def duplicate(x:str) -> str:
  return x * 2

print("Start")
[[my_convenience_macro(3, 'Hello', duplicate)]]
print("Mid")
[[my_convencience_macro(5, 'Goodbye', (x) -> (x))]]
print("End")

But this could equally be done via function calls, which contradicts the original idea of replacing repetititve nested code.

evhub commented 1 year ago

>> and << are bitwise shift operators in Python and thus cannot be redefined by Coconut (even as custom operators). Same with [[ and ]], which just enclose a list within a list.

Regardless, I'm going to close this as a duplicate of #102. If I end up implementing macros, it'll probably be by adopting some variant of PEP 638.