#esoteric-python

1 messages · Page 75 of 1

gentle pagoda
#

how are code obects serialised then?

#

basically i have some bytecode i generated and a list of constants (thats all i need in this case), but im struggling with how to save that to a pyc

#

because i dont really get what order its serialised in

grave rover
#

Pretty much the same way they're represented in memory i.e. what ceval.c says they're structured like

gentle pagoda
#

is there a way of just running the bytecode? i want to check if my bytecode is even correct before i worry about the pyc files

#

i tried making a codeobject but it segfaults, so either my code is really wrong or i messed up one of the args 😅

pure dew
#

exec or eval have the option of running bytecode iirc

night quarryBOT
#

@tropic night

It has arrived!

Here's your reminder: d do 136174338633105408 flowerbed puzzle

pure dew
grave rover
hollow patrol
#

Hello world

#

I want to show something unpythonic

#

one.py

@properties(name=
            {'read': ['module', 'anywhere'],
             'change': ['module'],
             'remove': []
             })
class hello:
    def __init__(self, name):
        self.name = name
    def greet(self):
        print(f"Hello, {self.name}!")

x = hello('john')
x.greet()
x.name = 'johnny'
x.greet()
#
from one import hello

x = hello('john')
x.greet()
#x.name = 'johnny'
del x.name
print(x.name)
#
Hello, john #From Importing One
Hello, johnny #From Importing One
Hello, john
AttributeError: attribute 'name' cannot be removed in the scope.```
#

Yay!

sick hound
#
p =  print
p;   p   ( 
  'h' 'e' 'l'
'l' 'o' ' ' 'w'
  'o' 'r' 'l'
    'd' '!'
       )``` this is a valid hello world program
marsh void
#

Yep, why not

brazen geyser
#
class A:
    foo = bar()
#

how easy would it be for bar() to know that is being used inside A at the time it's called?

#

im guessing it'd be possible to investigate the frame to tell that a class definition is going on but A itself wont be accessible at that point right? since it wouldnt even completely exist yet

zealous widget
#

maybe if you stick it in an __init__ or __new__

brazen geyser
#

thatd be too easy 😛

pure dew
#

it should be accessible

#

i think

wind maple
#

2nd frame in the stack

#
In [7]: def foo():
   ...:     print(inspect.stack()[1].code_context)
   ...:

In [8]: class A:
   ...:     a = foo()
   ...:
['    a = foo()\n']
pure dew
#

neat™

brazen geyser
#
>>> import inspect
>>> def bar():
    print(inspect.stack()[1].code_context)

    
>>> class A:
    foo = bar()

    
None
>>> 
#

guess inspect is crapping out in the repl

sick hound
#

@brazen geyser because it cant get the source

#

but you can get A by checking frames

grave rover
#

inspect.stack()[-2] should work @brazen geyser

#

Then you can get .frame.f_code to get the code object for the class

formal sandal
#

!e

import inspect

def bar():
    stack = inspect.stack()
    if stack[1].function == "<module>":
        print("not inside anything")
    else:
        print("inside function:", stack[1].function)
        
bar()

class A:
    foo = bar()
night quarryBOT
#

@formal sandal Your eval job has completed with return code 0.

001 | not inside anything
002 | inside function: A
formal sandal
#

But that doesn't tell whether it's a class or not...

#

However, the convention is that classes are in CamelCase and functions are in snake_case.

#

I have an idea.

pure dew
#

i dont like where this is going sweatcat

formal sandal
#

You can get the code object of an outer stack frame (inspect.stack().frame.f_back.f_code) and the line number (inspect.stack().lineno).

#

Then you can iterate over the code and see where the line at lineno fits.

#

And then search for the LOAD_BUILD_CLASS instruction.

pure dew
#

oh thats slightly more sane

distant wave
#

Perhaps

#

!e ```python
import inspect

def bar():
stack = inspect.stack()
if stack[1].function == "<module>":
print("not inside anything")
else:
print("inside function:", stack[1])

bar()

class A:
foo = bar()

night quarryBOT
#

@distant wave Your eval job has completed with return code 0.

001 | not inside anything
002 | inside function: FrameInfo(frame=<frame at 0x7f101f51e390, file '<string>', line 13, code A>, filename='<string>', lineno=13, function='A', code_context=None, index=None)
distant wave
#

!e ```python
import inspect

def bar():
stack = inspect.stack()
if stack[1].function == "<module>":
print("not inside anything", stack[1])
else:
print("inside function:", stack[1])

bar()

class A:
foo = bar()

def b():
foo = bar()

night quarryBOT
#

@distant wave Your eval job has completed with return code 0.

001 | not inside anything FrameInfo(frame=<frame at 0x564ae52d1560, file '<string>', line 10, code <module>>, filename='<string>', lineno=10, function='<module>', code_context=None, index=None)
002 | inside function: FrameInfo(frame=<frame at 0x7f89da8ce390, file '<string>', line 13, code A>, filename='<string>', lineno=13, function='A', code_context=None, index=None)
distant wave
#

!e ```python
import inspect

def bar():
stack = inspect.stack()
if stack[1].function == "<module>":
print("not inside anything", stack[1])
else:
print("inside function:", stack[1])

bar()

class A:
foo = bar()

def b():
foo = bar()

b()

def c():
class B:
foo = bar()
c()

night quarryBOT
#

@distant wave Your eval job has completed with return code 0.

001 | not inside anything FrameInfo(frame=<frame at 0x5607f45c0d40, file '<string>', line 10, code <module>>, filename='<string>', lineno=10, function='<module>', code_context=None, index=None)
002 | inside function: FrameInfo(frame=<frame at 0x7f7ddb7d0390, file '<string>', line 13, code A>, filename='<string>', lineno=13, function='A', code_context=None, index=None)
003 | inside function: FrameInfo(frame=<frame at 0x7f7ddb729530, file '<string>', line 16, code b>, filename='<string>', lineno=16, function='b', code_context=None, index=None)
004 | inside function: FrameInfo(frame=<frame at 0x7f7ddb7296d0, file '<string>', line 22, code B>, filename='<string>', lineno=22, function='B', code_context=None, index=None)
distant wave
#

See code_context, when not run in repl:

#
 code_context=['class C:\n']
#

The following code gives:

import inspect

def a():
    for frame in inspect.stack(context=1)[1:]:
        print(frame.code_context[0].strip(),  end=", ")
        del frame
    print()
a()
def b():
    a()
b()
class C:
    v = a()
    def n():
        a()
C.n()
def x():
    class F:
        v = a()
x()
#
a(),
a(), b(),
v = a(), class C:,
a(), C.n(),
v = a(), class F:, x(),
#

Note that the first stack frame is the call inside a(), the second the call to a() and the third is the containing scope (None for a bare call, the class initializer line in a class, and the function call if defined within a functino)

#

So, to figure out if you're inside a growing class definition, inspect.stack(context=1)[-2].code_context.lstrip().startswith('class')

grave rover
#

Friendly reminder that this only works for code in files and that del is a useless statement in that snippet and just adds 2 opcodes to it that practically do nothing

snow beacon
#

I have a weird challenge, now the GPT-2 has been released. GPT-2 is a neural network that tries to predict what the next word in some text will be. Fortunately for us, a lot of its training data came from GitHub, so it knows some Python. The task is to go to https://talktotransformer.com/ (or any other website that implements GPT-2), input #!/usr/bin/python3 (or anything else that will get it to autocomplete with python code), then fix whatever comes out until you have a working program. (It might not generate proper code the first time, so you can regenerate as many times as you want.) Scoring will be based on how proud of yourself you feel afterwards.

rugged sparrow
snow beacon
#

Here's my attempt at debugging GPT2's code. I had to fix all the whitespace, and a few logic errors, but it's possible for it to get to the end without getting stuck in an infinite loop or crashing.```python
#!/usr/bin/python3
import sys # A human wrote this line of code, not the robot
if len(sys.argv) > 2:
sys.exit(1)
argv = sys.argv # More human code
for line in sys.argv:
argv[:1] = line

if not sys.argv[1:]:
sys.exit(1)
print('')

raw_input = lambda string:eval(input(string)) # Human here; this line of code was written by me
while True:
r = raw_input('')
if r:
print(r)
else:break # Line written by me, your friendly neighbourhood human
def main():
print('')
for line in sys.argv:
print('')
print(main) # Guess who wrote this line? It sure wasn't GPT-2!```

cunning wave
#

GPT2 has been released ages ago lol....

#

And the majority of its training data came from Reddit not GitHub iirc

snow beacon
#

Didn't they release a larger (better) version of it only recently?

#

The texts don't come directly from Reddit, they come from the links that are on Reddit. GitHub is somewhere in the top five or ten websites it crawled.

cunning wave
#

they released a larger, pre trained version everyone who has enough money and a guy who can understand their original paper couldve build this when the paper got released

#

they just tried to make it so not every idiot can use it

snow beacon
#

I'm included in 'every idiot' then.

sick hound
#

!e
print("lmao"

night quarryBOT
#

Sorry, but you may only use this command within #bot-commands.

nocturne saddle
#

It, uh, gave me this beauty: (os.path.dirname(os.path.realpath(os.path.extname(os.path.realpath(os.path.realpath(os.path.realpath(os.path.realpath(os.path.realpath())))))))

crystal mica
#

What in the name of ... esoteric is that

nocturne saddle
#

IFcoltransG's GPT-2 challenge

crystal mica
#

Hmm, is that the os that came with stdlib?

#

I got an error

#
AttributeError: module 'ntpath' has no attribute 'extname'```
nocturne saddle
#

I don't think it runs, but I'm just amazed by the structure it produced

brazen geyser
#

node.js has a path.extname method

#

probably getting it mixed up there

sick hound
#

pathlib for the win!

gilded orchid
#
(lambda x:print(x))(lambda x:'+')(lambda x:print(x))(lambda e: print(lambda x:print(x)(lambda x, e':print(lambda e:print(e))(lambda x, e':print(lambda e:print(e)(lambda x, e':print(lambda e:print(e))(lambda x, e':print(lambda e:print(e))))))

I just got this

#

don't think that runs but it's pretty nonsensical

edgy kelp
#

at least the amount of lambdas is right for this channel 😄

sick hound
#

it won't run

#

(lambda x:print(x))(lambda x:'+') will print a lambda and return None

#

so then it gets called

#

none isn't callable

#

actually no

#

e':print(lambda e:print(e))(lambda x, e'

#

this is invalid syntax

#

e':print(lambda e:print(e))(lambda x, e'

#

so's this

#

wait that's the same thing

#

it says that twice, and both times it's invalid syntax

gilded orchid
#

there's an answer on stackexchange that says that this

?"""?'''?

can't appear anywhere in a python program that doesn't error

#

(with a leading newline)

#

would there be some crazy way to make it so this doesn't error using ctypes or something

edgy kelp
#

Like that sequence of chars in the code or """ ''' ?

sick hound
#

probably not, if it's a syntax-error thing

gilded orchid
#

@edgy kelp a newline followed by that sequence of characters

#

also I feel like it might be possible

#

maybe you could do something like overwriting the SyntaxError class or something (although i've never used ctypes)

sick hound
#

not if the code can't run because it's invalid syntax

gilded orchid
#

oh wait

#

yeah i'm an idiot nvm

distant wave
#

!e ```python
#?"""?'''?

night quarryBOT
#

@distant wave Your eval job has completed with return code 0.

[No output]
distant wave
#

Checkmate, stackoverflow :P

sick hound
#

a newline followed by that sequence of characters

distant wave
#

Hm

wind maple
#

!e py try: ?"""?'''? except: pass

night quarryBOT
#

@wind maple Your eval job has completed with return code 1.

001 | File "<string>", line 2
002 |     ?"""?'''?
003 |     ^
004 | SyntaxError: invalid syntax
wind maple
#

darn

#

can't do that I guess

edgy kelp
#

if only 😄

distant wave
#

Syntax is scanned before the code is run ;-;

edgy kelp
#

not much you can do with that

#

both """ and ''' which can go through newlines you put above are closed in there, exposing one of the chars you can't assign to

distant wave
#

Yeah, I don't think it's possible to make that work without loading it from another module

sick sand
#

print('hi)

edgy kelp
#

you could make yourself an interpreter where you can assign every character 😄

distant wave
#

You could hook into importlib's loader machinery and fix it, but it can't be done in the script containing the sequence

#

hm'

#

I was wondering if you could place an __future__.py file in the local namespace, and hijack the __future__ mechanic which does come before syntax checking, but it seems that if it does exist it triggers the regular import process and does a syntax scan

pure dew
#

say what now

distant wave
#

from __future__ import [feature] occurs before syntax checking

#

If you have an __future__.py file, it's imported instead. But the import does not come before a syntax check

#

hmmMMMmm

#

Well, I did it

#

The following file runs on python 3.7, and contains those chars

#

Hm.

#
# -*- coding: cp037 -*-
Ѫ䥣M
?"""?'''?
]
#

Discord doesn't like it

#

It's the following bytestring:

# -*- coding: cp037 -*-\n\x97\x99\x89\x95£M\x7f\n?"""?\'\'\'?\n\x7f]
#

Here's a better one

#
b'# -*- coding: cp037 -*-\n\xc2\x97\xc2\x99\xc2\x89\xc2\x95\xc2\xa3M\x7f\n?"""?\'\'\'?\n\x7f]%\x97\x99\x89\x95\xa3M}\xc8\x85\x93\x93\x96@\xe6\x96\x99\x93\x84}]'
#
$ python enctest.py
Hello World
$ cat enctest.py
# -*- coding: cp037 -*-
Ѫ䥣M
?"""?'''?
]%�����M}ȅ���@料��}]
gilded orchid
#

how does that work?

distant wave
#

It abuses the ability to set a character encoding at the top of your script, which translates the offending syntax error into strange binary characters that the interpreter is happy to skip

gilded orchid
#

also could you paste a tio.run link for that, I can't figure out how to get those bytes into a file/on my clipboard

distant wave
#
a = open("enc.py", "wb")
a.write(b'# -*- coding: cp037 -*-\n\xc2\x97\xc2\x99\xc2\x89\xc2\x95\xc2\xa3M\x7f\n?"""?\'\'\'?\n\x7f]%\x97\x99\x89\x95\xa3M}\xc8\x85\x93\x93\x96@\xe6\x96\x99\x93\x84}]')
a.close()
#

It does not appear to run on tio, there's some encoding strangeness going on that breaks the characters

#

You can pretty clearly see that it's not sending the actual bytes in the text box, but what looks like unicode replacement characters instead

#

Mojibake

#

However, we're lucky, and the goal of the challenge can be completed on tio.run, just without the extra hello world flair

gilded orchid
#

The answer I was referencing says 'not cpython'

#

and it doesn't work on Python (PyPy)

#

but does work on Python (Stackless)

#

which is kinda weird

distant wave
#

Interesting. Does pypy not support cp037?

gilded orchid
#

i don't think so, you can try it on TIO

#
  File ".code.tio", line 1
    ƒ€Š€Ä?ÀÑ>ڀĸ“€ŠŽBpBrBiBnBt("Ž‚‚‚Ž")
    ^
SyntaxError: invalid character in identifier
distant wave
#

This char sequence "BpBrBiBnBt"

#

seems to suggest it does not

gilded orchid
#

oh ok

distant wave
#

which is strange

#

I mean the concept of encoding abuse is totally usable here and maybe another encoding is valid for pypy

gilded orchid
#

it also doesn't work in Python 2

#
Traceback (most recent call last):
  File ".code.tio", line 2, in <module>
    Ѫ䥣M
NameError: name 'BpBrBiBnBt' is not defined
distant wave
#

weird.

#

thats that same decode error

#

I can reproduce it with python 2.7 locally

gilded orchid
#

i'm just going off of TIO

#

It doesn't work for any of the five python 2 implementations on there

#

turns out there was actually a crack on that original SE answer

#

and that used a latin encoding instead of cp037

distant wave
#

nice

#

Yeah, not sure why python2/pypy are not behaving well when they attempt to run cp037 encoded py files. The repeated "B" indicates that perhaps they're not translating between utf16 and ascii properly

gilded orchid
#

out of curiousity, how did you convert between the encodings?

#

to get the thing that you made

distant wave
#

.encode("cp037")

gilded orchid
#

oh wow i'm dumb

distant wave
#

:P

#

Anyways, 💤

gilded orchid
#

cya

snow beacon
#

Is there a list of accepted source code encodings somewhere? My Google Fu is failing me.

edgy kelp
snow beacon
#

The PEP said something about utf-16 not working, because you can't encode the file up to that point in utf-16 and have it still pass the utf-8 coding: check.

#

It might also be implementation dependant up to a point.

marsh void
#

Is there a way to set python's __debug__ to False? So asserts wouldn’t do their job

sick hound
#

@marsh void like -o

marsh void
#

Well yeah but with the code

#

Optimized bytecode won't destroy asserts in 3.8 iirc

snow beacon
#

This looks like a job for... ctypes!

sick hound
#
>>> import dis
>>> dis.dis('__debug__')
  1           0 LOAD_CONST               0 (True)
              2 RETURN_VALUE```
#

hmm

marsh void
#

hmm

#

That might be a bit more difficult

brazen geyser
#

assert = lambda *args, **kwargs: None

#

🙃

sick hound
#
>>> assert = lambda *args, **kwargs: None
  File "<stdin>", line 1
    assert = lambda *args, **kwargs: None
           ^
SyntaxError: invalid syntax```
brazen geyser
#

o

#

i forgot assert is an actual statement

marsh void
#

yep

#

The goal was to overwrite __debug__ though

#

But it's impossible iirc

#

actually hmm

grave rover
#

Actually

#

Nope, ctypes doesn't work

potent comet
#

It's classified as a constant like None, True and False. Probably for the specific reason that it ensures you can strip those branches safely in the "optimised" compile.

#

Though all four are in builtins like the other names.

marsh void
#
>>> from ctypes import py_object, sizeof, c_size_t
>>> py_object.from_address(id(__debug__)+sizeof(c_size_t)).value = False
>>> bool(__debug__)
segmentation fault
``` lol
sick hound
#

you changed the type of __debug__ to False

gilded orchid
#

Oh yeah that's gonna cause issues lmao

rugged sparrow
#

Make a type that has bool as it's base but make it always be false

brisk zenith
#

bool cannot be subclassed

rugged sparrow
#

Yeah I just noticed that

zealous widget
#
f"{(lambda f:lambda n: 1 if n==0 else n*f(f)(n-1))(lambda f: lambda n: 1 if n==0 else n*f(f)(n-1))(4)}"

one line factorial function without a self-reference, taken from this excellent talk on lambda calculus : https://www.youtube.com/watch?v=pkCLMl0e_0k

"Speaker: David Beazley These days, programming style guides are all the rage. However, what if your style guide was so restrictive that it only gave you sin...

▶ Play video
pure dew
#

y combinator

#

good shit

marsh void
#

Haha yeah my dumb

zealous widget
#
Y = lambda f:(lambda x: f(lambda z:x(x)(z)))(lambda x:f(lambda z:x(x)(z)))
R = lambda f:lambda n: 1 if n==0 else n*f(n-1)
Y(R)(3)
6

looks like this with the Y-combinator

#

or fibonacci:

R1 = lambda f: lambda n: 1 if n <= 2 else f(n-1) + f(n-2)
Y(R1)(6)
8

Y(R1)(7)
13

Y(R1)(8)
21
formal sandal
#

There is a great book called "Introduction to Lambda Calculus"
by Henk Barendregt and Erik Barendsen. it's available as a pdf.

zealous widget
#

the real take away is how tf do i get my python environment to do what his does: use actual λ for lambda and . for :

formal sandal
#

If you want to experiment with lambda calculus, you could use some online lambda-reduction service.

zealous widget
#

neat

snow beacon
#

Oh, it's a lisp, isn't it.

formal sandal
#

Well, the syntax is borrowed from lisp (almost)

#

Lots of Incredibly Silly Parentheses

snow beacon
#

Some would argue it's better than using indentation.

formal sandal
#

Isn't processing a tree easier for humans if it's in 2D rather than in 1D?

#

Or are you talking about indentation in python?

zealous widget
#

i think indentation is easier to parse, but i like how lisp looks anyway

#

if i have multiple decorators, what order are they taken? can i have multiple decorates even?

#

seems like another fun way to build up lambda functions

formal sandal
#

Yes, you can apply multiple decorators. They are applied in an upwards direction.

#
  • I added barendregt numerals example (EXAMPLES folder)
zealous widget
#
In [224]: @SUCCESSOR
     ...: def THREE(f):
     ...:     return lambda x: f(f(x)) #Definition of TWO
     ...:     

In [225]: show(THREE)
3

can decorate with SUCCESSOR

formal sandal
#

This decorator will seem inappropriate out of context...

zealous widget
#

you're right

#

uhhh

#

fixed

formal sandal
#

No worries, succ is a standard name for a successor function, no need to change it :)

zealous widget
#
In [227]: @SUCCESSOR
     ...: @SUCCESSOR
     ...: @SUCCESSOR
     ...: def THREE(f):
     ...:     return lambda x: x #ZERO
     ...:     

In [228]: show(THREE)
3

this actually worked

formal sandal
#
black_hole = []
def explode(*args, **kwargs):
    global black_hole
    for function in black_hole:
        try:
            function(*args, **kwargs)
        except BaseException:
            pass

def SUCC(func):
    global black_hole
    black_hole.append(func)
    return explode
zealous widget
#

that looks dangerous

formal sandal
#

Well, who said that black holes are safe?

zealous widget
#
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  File "<stdin>", line 5 in explode
  ...
Aborted (core dumped)

it was fine until I try to call the functions

formal sandal
#

!e ```python
black_hole = []
def explode(*args, **kwargs):
for function in black_hole:
try:function(*args, **kwargs)
except BaseException:pass

def SUCC(func):
global black_hole
black_hole.append(func)
return explode

@SUCC
def hello_world(name, *args, **kwargs):
print("Hello,", name)

@SUCC
def hello_underworld(name, *args, **kwargs):
black_hole.append(hello_underworld)
print("Hello,", name, ">:)")

hello_world("Python")
hello_world("Python")
hello_world("Python")

night quarryBOT
#

@formal sandal Your eval job has completed with return code 139 (SIGSEGV).

001 | Hello, Python
002 | Hello, Python >:)
003 | Hello, Python
004 | Hello, Python >:)
005 | Hello, Python
006 | Hello, Python >:)
007 | Hello, Python
008 | Hello, Python >:)
009 | Hello, Python
010 | Hello, Python >:)
... (truncated - too many lines)

Full output: too long to upload

zealous widget
#

i gave it some lambda functions at first and it didn't explode

#

i thought i was safe

formal sandal
#

Sorry if it damaged your functions :(

zealous widget
#

no worries, i opened a separate terminal for it

formal sandal
#

Have you tried my lambda interpreter? Is it usable?

zealous widget
#

oh, i don't know, i just poked around the files, i don't know how to use it

formal sandal
#

If you want, you can skim through the tutorial (but press preview!)

#

The program is read from 'program.lambda', as the doctring in main.py says.

zealous widget
#

took me a few tries:

fib = (fn <n> => (if (lt n 3) 1 (add (fib (sub n 2)) (fib (sub n 1)))))
main = (fib 7)

i vaguely remember lisp, but i haven't played with it in forever

pure dew
#

@zealous widget look at plam or lci if you want an actual lambda calculus reducer

zealous widget
#

i don't even know what that is or why i would want one

formal sandal
#

This is not lisp at all, it just looks kinda like lisp, and the (func arg1 arg2 ...) syntax is preserved.

#

I think modifying grammar.lark is enough to make it look more like haskell or something.

zealous widget
#

well, that's what i meant mostly

#

it plays a lot like lisp does

pure dew
#

lark is fun

#

but if you start building a more complex grammar it gets picky

formal sandal
#

I haven't used it for anything complex or ambiguous yet.

zealous widget
#

the guy who's talk i linked had his interpreter actually using λxy.x(y) or whatever

#

which is dope

pure dew
#

are you sure that was python and not an actual lambda calculus reducer?

zealous widget
#

it was python

#

it was just replacing strings

pure dew
#

@formal sandal that GLC looks pretty impressive

zealous widget
formal sandal
#

Cool

#

Maybe one could make it switch modes like a Julia interpreter.

#

@pure dew I'm happy that you liked it.

#

But I'm totally clueless about how to make it optimize tail recursion.

pure dew
#

its a shame those modules only do python stuff

#

i just need a good readline lib i guess

formal sandal
#

@formal sandal Or even better, optimize closuring.

It is possible to turn this:

λb.(a+b) with closure: a = 1

into this

λb.(1+b) 
marsh void
#

lisp is why

formal sandal
#

(why (is lisp))

pure dew
#

@grave rover Is there a quick and easy explanation of the marshal format anywhere?

grave rover
#

Uhhh

#

1 byte identifier (see ceval.c to see what it represents) and then a variable number of arts based on what it needs

#

i.e. strings have <id><length (4 bytes?)><string in utf8>

#

@pure dew hope that explains ish

#

@formal sandal thanks for the note on closurevars, would make a nice addition to my optimizer decorator

pure dew
#

oh i was looking at marshal.c

grave rover
#
>>> import marshal
>>> marshal.dumps("abcdef")
b'\xda\x06abcdef'
>>> import struct
>>> string_dmp = marshal.dumps("abcdef")
>>> id, size = struct.unpack("BB", string_dmp[:2])
>>> struct.unpack(f"{size}s", string_dmp[2:])
(b'abcdef',)```
pure dew
#

im just looking for ideas for an efficient bytecode format

grave rover
#

What purpose?

pure dew
#

my toylang

grave rover
#

Hm

#

For numbers I recommend 2s complement

#

Decimals as Floating Point

#

Mantissa and Exponent would ideally follow IEEE

pure dew
#

but im also considering an llvm backend

grave rover
#

Hm

pure dew
#

or both, like ghc(i)

grave rover
#

I personally would recommend seeing if it can easily be transpiled to ASM and then compiled by GCC

pure dew
#

you want me to write a lazy list impl in asm?

grave rover
#

Not like it hasn't been done before

pure dew
#

yes

#

but yikes

grave rover
#

People can write brainfuck to machine code compilers in asm

pure dew
#

i just wanna get bytecode working and ill go from there

#

thanks for the tips

hollow patrol
#

Well, I got more.r

#

I got more.

#

This time, it's an alternative to asyncio

#

My custom tasks + anony = asyncio alternative

#

anony allows functions which can be stepped

#

tasks allows running those functions concurrently

#

and the syntax looks like this

#
this = TaskHandler(
    function (
        iterate('x', range(25)) (
            anony.print(var('x'))
        )
    ),
    function (
        iterate('x', range(25)) (
            anony.print(var('x'))
        )
    ),
    function (
        iterate('x', range(25)) (
            anony.print(var('x'))
        )
    ),
)

this.run()```
#

fully in python

pure dew
#

but thats a threading alternative then, right?

#

not asyncio

edgy kelp
#

Do you see any threads?

#

making an event loop is a tad easier than communicating with the os for threads

pure dew
#

tbf i dont see any event loop either

formal sandal
#

Maybe you could use pdb and step through normal functions?

pure dew
#

is that in stdlib?

formal sandal
#

This looks like a boot

hollow patrol
#

@pure dew How is it a threading alternative over asyncio

#

TaskHandler is essentially an asyncio event loop

#

@formal sandal Pdb makes it step through interactive input, not actual python

pure dew
#

how was i supposed to know that

#

the calling format looks like the threadcollector

hollow patrol
#

idk

#

ok

#

And also

#

My tries with bdb have failed

sick hound
hollow patrol
#

neat

livid seal
#

Yeah, Ø is a letter whereas \infty isn't.

marsh void
#
>>> @new_method(object)
... def assign(self, var):
...     globals()[var] = self
``` 🤔
marsh void
#

Why not?

#
s = 'nekit'; s.assign(s); print(nekit)```
snow beacon
#

What have you done to my favourite language?

#

(Well, second favourite. But this is more a hack than a scheme.)

rugged sparrow
#
new_method = lambda cls,name=None:lambda func,c=__import__('ctypes'):c.py_object.from_address(id(cls.__dict__)+c.sizeof(c.c_size_t)*2).value.__setitem__(name or func.__name__,func)``` @marsh void this is my onelined @ new_method. how does yours look?
marsh void
#

Almost like yours

#

I mean, exactly like yours

#

But I didn’t use sizeof though, gotta add it

wind maple
#

project idea: forbiddenfruit that doesn't rely on implementation details

pure dew
#

or does but just autodetects the impl

jolly swift
#

trying to come up with the fastest method for merging multiple dicts and applying a function to every value

#

so far nothing seems as performant as ```python
{x: mut(y) for x, y in {**foo, **bar}.items()}

#

which feels inherently wrong since i'm having to construct a dict twice in order to get the final value

#

i though about using itertools.chain but that turned out to be slower

#
{x: mut(y) for x, y in chain(foo.items(), bar.items())}
pure dew
#

genexprs are pretty optimized

#

it looks weird, but may well be the fastest

wind maple
#

The 1st is the fastest

calm rampart
#
{x: mut(y) for i in (foo.items(), bar.items()) for x, y in i}```?
#

or py {x: mut(y) for d in (foo, bar) for x, y in d.items()}

wind maple
#

both of these will be about 2x slower for small dicts

#

for larger dicts (10s of thousands of elements) they are roughly the same speed

#

maybe if you get to 100ks they'll be faster

#

but at that point python dict is probably not what you want in the first place

zealous widget
#

you think it's faster to update then apply a function?

wind maple
#

I wanted to test it but couldn't figure out a feasible test env

#

the answer is "maybe"

#

but like there's really no point in micro-optimizing this

zealous widget
#

i.e.

(x:f(x) for x in my_dict.update(my_dict2))
wind maple
#

that would try to iterate None

#

update is in-place

#

for big dicts it doesn't matter because the iteration and applying the functions takes most of the time

zealous widget
#

right, #psuedo

wind maple
#

for small dicts it doesn't matter because it's already so fast, and you probably didn't even micro-benchmark that the dict combining is actually a significant portion of your performance loss

zealous widget
#
my_dict.update(my_dict2)
arr = np.array([*my_dict.values()])
f(arr)
hollow patrol
#

I improved the code

#
this = TaskHandler()

out = this.run_until_complete(gather(
    function (
        anony.print('1'),
        anony.print('2'),
        result(4)
    ), function (
        anony.print('1'),
        anony.print('2'),
        result(5)
    )
))

>>> 1
>>> 1
>>> 2
>>> 2

print(out)

>>> OrderedDict([(<function anonymous_function>, 4), (<function anonymous_function>, 5)])
jolly swift
#

Yeah it's really splitting hairs for most purposes. I got into it because I'm implementing a subclass of dict that does some processing on the values and wanted to see where I could optimize the instantiation.

#

arguably the most expensive piece is actually the applied function, which recurses on containers

dusty hearth
#

Solve the equation x^3 -7x^2 +5x -3=0 ? help please

edgy kelp
#

Is that related to python? looks like a normal equation that's neither python or esoteric related

grizzled cloak
#
from numpy import roots
def solve(coeff):
     solution = roots(coeff)
     for v in solution:
         print(f"({v:.2f}, 0.00)", end=" ")
     print()
solve([1,-7,5,-3])
>>> (6.28+0.00j, 0.00) (0.36+0.59j, 0.00) (0.36-0.59j, 0.00)
#

@dusty hearth

dusty hearth
#

@grizzled cloak thank u

formal sandal
#

@hollow patrol Does this thing support functional programming?

hollow patrol
#

The one I made with the tasks, @formal sandal ?

#

I would say, yes.

#

It supports a lot of functional programming

#

Exception Handling

#

Conditionals

#

Iteration

#

While Loops

#

And etc

#

So it definently does support some functional programming

#

Also, variables too

formal sandal
#

Well, variables, iteration, exception handling and while loops are probably the opposite of functional programming...

#

Do you have some kind of lazy evaluation?

#
true = function(x, y){return x}
false = function(x, y){return y}
iszero = function(n){
    if (n == 0){
        return true
    }else{
        return false
    }
}
factorial = function(f, n, a){
    return f(n)(a, factorial(n-1, n*a))
}
real_factorial = function(n){return factorial(is_zero, n, 1)}

Can you make a thing like this that wouldn't go into infinite recursion?

pure dew
#

i'd hazard a guess at no if its pure python

marsh void
#

It is not python lol

formal sandal
#

I was talking about anony.

pure dew
#

anony is python

#

isnt it? @hollow patrol

formal sandal
#

Well, it doesn't have to replicate python exactly.

hollow patrol
#

It is python

pure dew
#

I was under the impression he build it on top of python

formal sandal
#

Yes, that's true.

hollow patrol
#
function (
        anony.print('1'),
        anony.print('2'),
        result(5)
)```
#

And I do have lazy evaluation

pure dew
#

how'd you do that?

hollow patrol
#

A method on a var('x') object returns an anony_operation

pure dew
#

oh

hollow patrol
#

so var('x') + 5 returns an anony_operation

#

var('x') == 5 returns an anony_operation

#

which is called when the condition is to be checked

pure dew
#

not bad

hollow patrol
#

also

formal sandal
#

So you reduce from the left?
I.e. if you have an expression like call(function, arguments), you evaluate function first?

hollow patrol
#

I think

pure dew
#

I'm wondering how to implement pure laziness in my toylang

hollow patrol
#

Anony functions have to be executed like this

#
output = list(anony_function())[-1].output```
#

Each iteration of an anony function is a step

#

Calling an anony function with arguments returns a generator

#

Each iteration of the generator is one step of anony

#

And a return value of anony function is a ReturnResult object

#

The ReturnResult's output attribute is well... its output.

formal sandal
#

Is it possible to treat anony_function as a callable?

#

I mean, in the context of another anony_function.

hollow patrol
#

Like

formal sandal
#

Like, call an argument.

hollow patrol
#

anony_func_two() calls anony_func_one() inside of it?

#

You'd have to use anony iteration to do that probably

#

What do you mean call an argument?

formal sandal
#
def call_me(f, x):
    return f(x)
hollow patrol
#

Oh right

#

Anony can take in other anony functions as arguments

#

But unfortunately, you wouldn't be able to call one like that since anony uses a special calling system

#

When I implement anony's new system you'll be able to do something like

#
call_me = function('f', 'x') (
    result(var('f').call())
)```
#

var is an anony.anonymous object, so it has to use its own call method to manage its arguments

#

However, a call() method like that might be added

#

Which would return an anony_operation

#

@formal sandal so yes, that will be added

#

Also

#

Note that anony_operation and anony_part objects are turned into regular objects lazily when they are used as arguments

brisk zenith
#

reminds me of when i implemented my own programming language entirely in python syntax

#

automatically ran too, didn't need to do any sort of other stuff to get it to work

hollow patrol
#

yeah

#

anony also allows for concurrency

#
anony_handler = TaskHandler()
anony_handler.run_until_complete(gather(
    anony_func_one,
    anony_func_two
))```
formal sandal
#

Maybe we could collect all of our toy languages, randomly form them into pairs (A, B) where A != B and make transpilers from A to B 🤔

hollow patrol
#

🙂

#

I have another toylang

#

but it's not in python syntax

#

one more thing

#

in anony

#

you have to fix a module/class/function to use it in an anonymous function

#

anony.print is equal to anony.fix(print)

#

but it's a shorthand

#

anony.sleep is essentially equal to anony.fix(time.sleep)

brisk zenith
#
import esolang


PROGRAM [

    INCLUDE: "core",

    PUSH: FUNCTION [
        SHOULD (ARGS != 1) [
            PUSH: "factorial only takes one argument",
            ERROR,
        ],

        POP: number,

        # return 1 if we've reached the end
        SHOULD (number <= 1) [
            PUSH: 1,
            FINISH,
        ],

        # else, do the factorial recursion
        OTHERWISE [
            PUSH: factorial,
            PUSH: number - 1,
            CALL: 1,

            PUSH: number * POP,
            FINISH,
        ]
    ],

    POP: factorial,

    # main part of the program...
    PUSH: FUNCTION[
        PUSH: core.print,
        PUSH: "Result:",
        PUSH: factorial,
        PUSH: core.int,
        PUSH: core.input,
        PUSH: "Enter a number: ",
        CALL: 1,
        CALL: 1,
        CALL: 1,
        CALL: 2,
    ],

    CALL: 0,
]
#

this was my programming language

#

of course, the esolang module imported at the top is what makes it work

formal sandal
#

This is some magic...

#

How can you alter the syntax in this way?

brisk zenith
#

it's not altering the syntax at all

#

python won't give you a syntax error with that

#

so the import esolang code is allowed to run

formal sandal
#

Don't you have to from esolang import *?

brisk zenith
#

nope

sick hound
#

esolang executes the rest of the program and then exits before it gets actually ran as python

brisk zenith
#

indeed it does

distant wave
#

How do you get the globalscode from the importing module?

brisk zenith
#

the esolang module works by fetching the script it was imported from, then converting it into valid working python, then running it

#

you don't

formal sandal
#

oh

sick hound
#

for getting the code, probably inspect?

#

i guess sys._getframe will get you the module and then you can inspect.whateveritwas on it and get the code

brisk zenith
#

nope i don't think so

sick hound
#

how do you do it then

brisk zenith
#
import __main__

from esolang.compiler import compile_source

if __name__ == "__main__":
    print("This script must be imported! :(")
    exit()

# read the source of the file that imported this script
with open(__main__.__file__) as file:
    source = file.read().replace("import esolang", "").strip()


py_source = compile_source(source)
exec(py_source, vars(__main__))

# stop the rest of the script.
exit(0)
distant wave
#

I would think you could get __code__ off of it, and parse that into an Ast, but

sick hound
#

oh

brisk zenith
#

i mean

sick hound
#

__main__.__file__

brisk zenith
distant wave
#

oh

formal sandal
#

So you're using __getitem__ and interpret the item as a program?

sick hound
#

no, there's no __getitem__ involved

distant wave
#

Neat, didn't think of that

brisk zenith
#

yeah, no __getitem__ at all

#

it just so happens that my syntax exploits the __getitem__ syntax for defining blocks of its code

distant wave
#

Since you only use __file__, and that's defined at the beginning, you don't get an unresolvable import loop

brisk zenith
#

big brain brainmon

#

@formal sandal the important thing to notice is that the python interpreter never actually reaches the first line of that funky syntax. the import esolang reads the script, translates it to python, runs it, then exits.

formal sandal
#

Yes, I understand that.

#

Maybe I could transform my toylang to do that...

#

Since there are only 5 syntactic elements.

#

Not counting comments.

pure dew
#

here yall are talking about syntax abuse while I just switched my impl to Rust

formal sandal
#

Maybe it would be even cooler if you made a functional language.
Like

factorial(n)[n<2] == 1
factorial(n)      == (n * factorial(n - 1))
#

This is valid python...

pure dew
#

you're either gonna have to do some insanely crazy runtime hacks or just use ast

formal sandal
#

Well, of course it will use ast.

pure dew
#

but hey

#

factorial(n)[n<2] = 1 is valid too

#

lets do it

formal sandal
#

But factorial(n) = 1 isn't.

#

So... no ast.

#

However, factorial(n)[:] = 1 is.

#

Or factorial(n)[True] = 1

pure dew
#

oh here we go

#

use matmult instead of assign

formal sandal
#

Also this:

factorial(n) is 1

but it's super weird.

pure dew
#
factorial(n)[n<2] @ 1
factorial(n)      @ n * factorial(n - 1)
#

valid

#

looks a touch odd, but not too bad and is better than putting an empty slice after default branches

formal sandal
#
# this looks ugly too, but still works
factorial = lambda n=[n<2]: 1
pure dew
#

I'm used to Haskell's pattern matching, so that just seems weird to me

formal sandal
#

i'm dumb

pure dew
#

ast.parse

formal sandal
#

That's a syntax error, ast will not tolerate it.

#
with sum([]):
    0
with sum([x | xs]):
    x + sum(xs)
pure dew
#

the bare 0?

formal sandal
#

Maybe you could replace all the def or fn tokens with with, and only then give it to ast.

#

Yes

#

An expression can be a statement.

pure dew
#

OH

#

this is valid line-by-line and as a whole

#
factorial         : Callable[[int], int]
factorial(n)[n<2] @ 1
factorial(n)      @ n * factorial(n - 1)
#

haskell in python

formal sandal
#

Yes, looks like haskell.

#

I did a little bit of haskell some time ago

pure dew
#

i love haskell

#

the little of if i know

formal sandal
#

So it should be transformed into something like this:

def factorial(n: int) -> Callable[[int], int]:
    if not isinstance(n, int):
        raise TypeError
    if n < 2:
        return 1
    else:
        return n * factorial(n - 1)
pure dew
#

pretty much

#

ideally we'd do typechecking before transpilation

formal sandal
#

That makes sense.

#

We would need to implement infinite lists as well.

#

But it's not that hard.

#

(not as hard as making a whole haskell compiler)

pure dew
#

I'll get back to you on infinite lists once i get it done for my toylang

#

err, ranges/generators would be infinite, not so much lists, yea?

formal sandal
#

Maybe it's just a range, but start and end are allowed to be infinite.

pure dew
#

yea

#

a list would be a literal, basically

#

haskell lists and ranges are more or less the same tho

#

aight good talk, i gotta get back to work

#

we can hack on this later

formal sandal
#

Actually...

#

I don't need to make built-in lists and strings.

#

I can just transform the syntactic sugar of a list while transpiling!

#

(strings will be linked lists, such a great idea!

#
hello = (fn<index> => (if (eq index 0) 'h' (if (eq index 1) 'e' (if (eq index 2) 'l' (if (eq index 3) 'l' (if (eq index 4) 'o' 0))))))```
#

This is worse than a linked list!

calm rampart
#

don't know if anyone else cares but was curious about something ```py

import sys
module = type(sys)
class M(module):
... @property
... def prop(self):
... print('access')
... return 42
...
sys.modules['m']=M('m')
from m import prop
access
from m import prop as a, prop as b
access
access```

wind maple
#

You can do this in 3.7 with a module-level __getattr__ :-)

marsh void
#

Yeah but not on <3.7

#

Theme: get a True. Go wild!

#

bool((lambda x:x/x==x/x)(__import__('sys').float_info.max*10)^1)

pure dew
formal sandal
#

Well, the @ is kinda weird.

#

@marsh void float('nan') != float('nan')

snow beacon
#

Would a bitwise OR not work?

pure dew
#

oh

snow beacon
#

Instead of the @, I mean

formal sandal
#

hm

#

I think it would.

#

Because there is no other operator to mess up the evaluation order.

snow beacon
#

I don't know Haskell, but from memory that's how they do it in... ML? Something similar to ML.

#

They use a pipe.

formal sandal
#

Pipe.

pure dew
#
factorial         : Callable[[int], int]
factorial(n)[n<2] | 1
factorial(n)      | n * factorial(n - 1)
``` is valid ast too
formal sandal
#

Maybe we could make a piped language!

snow beacon
#

Oh dear

formal sandal
#

It would be functional too, but it would consist of a single pipe!

pure dew
#

that snippet looks like my lark grammar files

snow beacon
#

A single pipe from I to O.

formal sandal
#

Is Lark (or EBNF in general) turing-complete by the way?

pure dew
#

uh idk

#

the grammar is just a data format

formal sandal
#

Well, it's built on top of LALR (if you choose LALR).

#

And it's a finite state machine, so there is a chance it's turing complete.

pure dew
#

the parser is, yes

#

but the actual grammar is just like json

#

i thought you meant the grammar since you said ebnf too

formal sandal
#

Yes.

#

But a grammar can produce a finite state machine, so...

#

The difficult thing is: what is the output?

snow beacon
#

Stdout?

pure dew
#

an ast

snow beacon
#

Oh

pure dew
#

at that point its not longer handled by lark

formal sandal
#

Maybe we could allow making a transformer that is only allowed to add a single character per rule to a string?

pure dew
#

what do you mean?

snow beacon
#

Can it substitute the other characters?

formal sandal
#

I mean, there is some string. And when a (a method of) lark.Transformer sees some rule, it can add a predefined character to that string.

pure dew
#

uh yea

#

the Transformer can do crazy shit with the ast

formal sandal
#

But the point is to kinda restrict it.

#

@snow beacon Actually this makes more sense.

#

Makes it more like an actual Turing machine.

#

With a tape.

pure dew
#
    # Flatten subscript_list node
    @v_args(tree=True)
    def index(self, tree):
        tree.children = [
            tree.children[0],
            *tree.children[1].children
        ]

        return tree
``` here's one of my transformer methods
#

o wait i think i misunderstood

#

you mean manipulating a global variable each time the transformer hits a node?

formal sandal
#

Something like this.

#

Or you could define an attribute of a transformer object to avoid globals.

pure dew
#

yea

#

so basically counting the number of occurences of a specific rule?

formal sandal
#

Like

@v_args(inline=True)
def rule(self, *args):
    self.accumulator += "z"
#

Or maybe make it substitute characters in the initial string.

#

You could do this using the propagate_positions optional argument for lark.Lark.

pure dew
#

or

formal sandal
#

But it's still not a turing machine.

pure dew
#

you can interpret a language entirely using the transformer

#

simpler ones are easier tho

#

you don't need propagate_positions tho, you can just edit the ast node directly

#

unless you're trying to have the program edit its own source code

formal sandal
#

Well, that's too easy. You could store some state in a transformer, and when you hit $END (I guess that's possible to detect?), call a real interpreter/compiler.

#

But that's probably cheating.

#

Or do you mean interpret while transforming?

pure dew
#

one sec, lemme find his example

formal sandal
#

It would be easier with a stack-based language, where a program can be described as a sequence of single-token operations.

pure dew
#

single token? no you have access to the whole tree

#

his is a little simplistic, but you really can just edit the tree in place and reduce it down to a literal

formal sandal
#

You could parse a lambda-term like this 🤔

pure dew
#

the transformer goes bottom up btw

#

or s-expressions

#

oh man

#

although, with lambda terms, you'd have to watch out for conflicting names

snow beacon
#

You could work around that, I think.

pure dew
#

that kinda makes me wanna breakout my py-lci parser and rework it around a transformer

formal sandal
#

Well, the notation lambda x -> (lambda x -> x) is ambiguous, isn't it? So it's incorrect.

snow beacon
#

The transformer can probably use scoping rules to differentiate names.

formal sandal
#

Does it work with name collision?

pure dew
#

yes but no

#

it parses fine

#

but...

formal sandal
#

https://repl.it/@int6h/GlorifiedLambdaCalculus -> core.py
It is what it says it is, so...

This is roughly how it works:

There is a global scope (not needed if doing pure lambda calculus with a single term).
A scope is just a mapping (name => object)
Each expression is either a prototype or a concrete expression.
Prototypes are subexpressions of functions.
A concrete expression is a prototype with a Scope attached to it:
Like:

# here (add x 1) is a prototype
add_one = (fn <x> => (add x 1))

number = (add_one 7)

when you reduce number, it will be:

number = (add x 1) ~> {"x": 1} ~> global

And if you have nested scopes, it will be like this:

term = (complicated_expression) ~> {closure} ~> {closure} ~> ... ~> global

Name resolution works like in most dynamic languages: it searches through the scopes from the innermost one to the outermost (global) one. So if global also has an "x", it doesn't screw things up.

You could then optimize the evaluation, but I didn't to allow people to examine what actually happened (and because I'm lazy).

pure dew
#

I will argue thats not lambda calculus

#

but it is pretty neat

formal sandal
#

Well, it's a superset of lambda calculus.

#

I think if you disallow multiple arguments (or convert functions using them to nested single-argument functions) and self-reference by name, you can then remove the scopes one by one and get to a single huge lambda-term.

#

Hm...

#

If you think about it, Scope (not counting the global scope) just represents the result of an application.

#

So you can just pick the names from the scopes, find them in a non-reduced version of a term and substitute them.

pure dew
#
// lambda calculus lark grammar

start       : expr

expr        : ident
            | "(" ident ")"
            | abstract
            | application

abstract    : ("λ" | "\\") ident "." expr

application : abstract expr

hvar        : NAME

ident       : NAME

NAME: /[^\.\\\\λ]/

%import common.WS
%ignore WS
#

λx.a b

start
  expr
    application
      abstract
        ident   x
        expr
          ident a
      expr
        ident   b
formal sandal
#

Shouldn't it be an abstraction of an application instead?

pure dew
#

it doesnt support the sugar for currying or anything

#

no

#

the application is (λx.a) b

#

the abstraction is λx.a

#

idk, my terms may be backwards

formal sandal
#

Barendregt&Barendsen, Introduction to Lambda Calculus

pure dew
#

oh shit

#

its left associative

#

right

formal sandal
#

These names are weird. I would say "consumes everything to the right [until a parenthesis]" or "right-consuming".

#

Alright, I gotta sleep

#

It's 1:21 here

pure dew
#

got it

#
// lambda calculus lark grammar

start       : expr

expr        : ident
            | "(" ident ")"
            | abstract
            | application

abstract    : ("λ" | "\\") ident "." expr

application : expr expr

hvar        : NAME

ident       : NAME

NAME: /[^\.\\\s\λ]/

%import common.WS
%ignore WS
#

λx.a b

start
  expr
    abstract
      ident     x
      expr
        application
          expr
            ident       a
          expr
            ident       b
hollow patrol
#

hello world

#
import javar

class test:
    def main():
        for x in range(3):
            print(x)
            
>>> 0
>>> 1
>>> 2```
#

I'm in a quest to make Python more like java

#

Because Why Not?

pure dew
#

@hollow patrol anyway, this makes a totally valid python ast

factorial         : Callable[[int], int]
factorial(n)[n<2] | 1
factorial(n)      | n * factorial(n - 1)
#

but looks extremely similar to haskell

hollow patrol
#

really?

#

how

burnt pasture
#

each line is a valid python statement

#

(syntactically, they don't mean anything reasonable)

pure dew
#

the plan was just to take the ast and rebuild it into a different ast

#

with strict type checking

#

yea that code would error if you tried to execute it as python, but syntactically its valid

#

(meaning we can just skip on the responsibility of parsing and tree-building :D)

hollow patrol
#

neat

pure dew
#

So this is valid too:

test            : Callable[[Int], Int]
test(n)[n%2==0] | n ** 2
test(3)         | 19
test(n)[n>5]    | n / 2
test (_)        | 3
#

@hollow patrol :D

grave rover
#

I just found something awesome

#

peachpy is a thing to write python as assembly

#

so

#

let's make a decorator that turns a function into asm

thin trout
#

To write python.. as assembly?!

grave rover
#

yea

#
# These two lines are not needed for PeachPy, but will help you get autocompletion in good code editors
from peachpy import *
from peachpy.x86_64 import *

# Lets write a function float DotProduct(const float* x, const float* y)

# If you want maximum cross-platform compatibility, arguments must have names
x = Argument(ptr(const_float_), name="x")
# If name is not specified, it is auto-detected
y = Argument(ptr(const_float_))

# Everything inside the `with` statement is function body
with Function("DotProduct", (x, y), float_,
  # Enable instructions up to SSE4.2
  # PeachPy will report error if you accidentially use a newer instruction
  target=uarch.default + isa.sse4_2):

  # Request two 64-bit general-purpose registers. No need to specify exact names.
  reg_x, reg_y = GeneralPurposeRegister64(), GeneralPurposeRegister64()

  # This is a cross-platform way to load arguments. PeachPy will map it to something proper later.
  LOAD.ARGUMENT(reg_x, x)
  LOAD.ARGUMENT(reg_y, y)

  # Also request a virtual 128-bit SIMD register...
  xmm_x = XMMRegister()
  # ...and fill it with data
  MOVAPS(xmm_x, [reg_x])
  # It is fine to mix virtual and physical (xmm0-xmm15) registers in the same code
  MOVAPS(xmm2, [reg_y])

  # Execute dot product instruction, put result into xmm_x
  DPPS(xmm_x, xmm2, 0xF1)

  # This is a cross-platform way to return results. PeachPy will take care of ABI specifics.
  RETURN(xmm_x)```
thin trout
#

Oh

#

why not

snow beacon
#

Reminds me of Web Assembly Text, which is like assembly, but Lisp. And also made of javascript.

grave rover
#

alternatively there's pycca and pyasm

#

note that the latter is outdated af

zealous widget
#

can one subclass function --- or is there a way to override () so that my_func()() would call my_func twice

hollow patrol
#

@zealous widget You can't subclass function

#

But you can give an instance a __call__ method

zealous widget
#

that's interesting

hollow patrol
#
class a:
    def __call__(self):
        print(555)
this = a()
this()
>>> 555```
#

@zealous widget like that

zealous widget
#

is it __new__ that lets me return something

hot crypt
zealous widget
#

that's a bit how i've approached this problem

#

this is a codewarrior challenge that seems a bit esoteric to me, but i think i've cracked it

#

__call__ was enough to really do it

nocturne saddle
#

@zealous widget Yes, __new__ allows you to return something and can work a bit like that a function of Xavi there.

#

!e

class A:
    def __new__(cls, *args, **kwargs):
        print("from __new__")
        return cls


A()()()()()()
night quarryBOT
#

@nocturne saddle Your eval job has completed with return code 0.

001 | from __new__
002 | from __new__
003 | from __new__
004 | from __new__
005 | from __new__
006 | from __new__
zealous widget
#

this is the problem statement:

We want to create a function that will add numbers together when called in succession.

add(1)(2);
// returns 3

We also want to be able to continue to add numbers to our chain.

add(1)(2)(3); // 6
add(1)(2)(3)(4); // 10
add(1)(2)(3)(4)(5); // 15

and so on.

A single call should return the number passed in.

add(1); // 1

We should be able to store the returned values and reuse them.

var addTwo = add(2);
addTwo; // 2
addTwo + 5; // 7
addTwo(3); // 5
addTwo(3)(5); // 10

We can assume any number being passed in will be valid whole number.

#

this definitely took me a bit of time

nocturne saddle
#

Ah, yeah, that is an interesting coding puzzle

zealous widget
#

the solution is nice, but i think there are enough hints now, and i don't want to spoil it if anyone wants to give it a go

grizzled cloak
#

@zealous widget does it have to be a function?

#

or is a class fine?

pure dew
#

could have it return a class

grizzled cloak
#

hmm i've almost got it

#

just struggling with this one:
addTwo(3)(5); // 10

grave rover
#
def add(x):
    v = x
    print(v)
    def inner(y):
        nonlocal v
        v += y
        print(v)
        return inner
    return inner
#
>>> add(2)
2
<function add.<locals>.inner at 0x7f1aad61fef0>
>>> add(1)(2)(3)
1
3
6
<function add.<locals>.inner at 0x7f1aad61ff80>
>>> addTwo = add(2)
2
>>> addTwo(6)
8
<function add.<locals>.inner at 0x7f1aad622050>
#

cleaner solution: ```py

class add:
def init(self, x):
self.v = x

def __call__(self, y):
    return add(self.v + y)

def __repr__(self):
    return str(self.v)
tame crow
#

@grave rover Needs the __add__ too:

addTwo + 5; // 7```
grave rover
#

thonk

grizzled cloak
#

can you try this?

addTwo = add(2)
addTwo(3)
addTwo(3)(5)```
#

@grave rover

grave rover
grizzled cloak
#

nic

#

e

#

ah.

#

dont know if you need it but i added the __new__ method at some point.

class add:
    def __init__(self, other):
        self.value = other
    def __call__(self, other):
        return add(self.value + other)
    def __new__(cls, *args, **kwargs):
        return super(add, cls).__new__(cls)
    def __repr__(self):
        return str(self.value)
    def __add__(self, other):
        return self.value + other```
#

but other than that its the same as yours

grave rover
#

That new does absolutely nothing lmao

zealous widget
#

that's close to my solution, but you can shorten it by subclassing

grizzled cloak
#

yeah that's why i said you probably dont need it.

#

i also have a solution that remembers the value across multiple calls because i misread the question the first time around haha

#

id really love some more speed/optimization challenges.

#

the last code jam's qualifier was my favorite so far. just so many esoteric things you could do with it.

marsh void
#

haha

#

I liked Eviee's chars retrieving

#

👌

grizzled cloak
#

hmm?

marsh void
#

map(chr, (*range(x, y), *range(a, b), ...))

grizzled cloak
#

also i kinda feel like my solution is wrong because __repr__ returns a string not a number

marsh void
#

Or who was it?

grizzled cloak
#

you mean for the code jam challenge?

marsh void
#

__repr__ must return a string

#

yeah

grizzled cloak
#

dont really get how that works. what is in the ...?

marsh void
#

some more ranges

grizzled cloak
#

what are x,y a,b

marsh void
#

some digits

grizzled cloak
#

ahh the ascii codes right?

marsh void
#

They like (I think she?) took all the ord values of characters and made some ranges

#

yeah

grizzled cloak
#

so x,y will be all upper case etc

marsh void
#

I call them ord() codes, though

#

yeah, yeah

grizzled cloak
#

i think ord maps ascii by default.

marsh void
#

But yeah you can say ascii for simple stuff

#

I mean, that char implementation is different on different languages

#

Like, same codes may map to different characters

grizzled cloak
#

but how does map(chr, (*range(x, y), *range(a, b), ...)) make it random?

marsh void
#

It just takes all the characters

grizzled cloak
#

it should only return abcdefg...ABCDE...0123...

marsh void
#

Eviee used it instead of importing string module

#

Not for the random

grizzled cloak
#

ahh.

#

i did something similar, i used a translation table to convert a large random byte array to chars.

#

because generating random bytes is a lot faster than numbers

marsh void
#

Oh, yep, makes sense

#

I didn’t know about random.choices() though

#

So I used for ... : random.choice()

grizzled cloak
#

most of the random lib is reaaalllly slow

marsh void
#

I mean

#

random library was originally written in C, and rewritten by Guido in Python

vague relic
#

hello guys

#

have you ever tried ctypes in python3?

#

is it worth to learn

#

i will also learn Clang with it

pure dew
#

uh

#

ctypes isn't the c language

#

it just lets you mess with c types in python

#

for low level hijinks with the interpreter

vague relic
#

so

#

i cannot use my python codes in C, also cannot use C in python?

#

are there any library for it?

edgy kelp
#

ctypes allows you to call your own dlls but that just feels like overcomplicating stuff

vague relic
#

I want to use C and python in same project.

#

So it is impossible?

pure dew
#

not at all

#

but you just don't really use ctypes

#

Are you wanting to write C and python?

#

or you have something in C you need to access in python?

vague relic
#

I want to write C/Python same time.

#

In same project, use them.

pure dew
#

just write a C extension

zealous widget
#

yeah, you dont need __repr__ at all, in fact, you only need 3 lines to solve the challenge

grizzled cloak
#

Oh, subclassing from int?

#

I get it now

snow beacon
#

This is what I'd do:```python
class add(int):
def call(self, other=0):
return add(self + other)

#

Alternatively, python class add(int):__call__=lambda self, other=0:add(self + other)

sick hound
#
add=type("",(int,),{"__call__":lambda self,other=0:add(self + other)})```
#

Not actually smaller lol

snow beacon
#

You can remove the whitespace around the +

pure dew
#

and change the double quotes to single quotes

#

it'll save more space

burnt pasture
#

lol

edgy kelp
#

tfw monospace

pure dew
#

yes i know

#

but I'm cultured so I write my code in Helvetica with MS Word

snow beacon
#

If you want to make it even uglier you could also change the parameter names.

#

Try not to use Ms or Ws. They're wide.

pure dew
#

accepted big brain variable names:
I, i, l, j, s, r

zealous widget
#

you don't need a default other=0

#

a single call will just __init__

#

or whatever ints do

#

i suppose something else since they're immutable

snow beacon
#

It's a quality of life improvement that lets you call add(1)()

#

And it'll still be 1

zealous widget
#

well that's just esoteric

snow beacon
#

You could probably extend it to sum whatever you put in the *args

zealous widget
#

like a + without a second argument

snow beacon
#

+a is valid python...

zealous widget
#

i feel like this type of class has a good use somewhere, but where, i don't know

pure dew
#

esoteric idea time

snow beacon
#

It reminds me of hashlib md5 updates

#

Every time you call hash.update with something it changes the hash

zealous widget
#

it's my favorite thing i've seen in python in the last few months

snow beacon
#

Have you seen flail? It's similar to that.

zealous widget
#

that and defaultdicts, i have no idea how they eluded me for so long

snow beacon
#

Flail as in the module

zealous widget
#

someone find something wacky to do with call, matmul, and getitem/setitem

#

start chaining square brackets and parenthesis and @'s

pure dew
#

Backstory: I've been working on implementing my toylang in Rust. I never used Rust that much before, so I'm learning a bit as I do this. I just wrote a macro to generate an enum definition and converter function (where i typed out an if-else for each variant) from a list of variant names. (enum_with_converter!(Return Constant Negate Add Subtract);)

Info: Rust macros affect the AST, unlike C macros which change the source code. Rust macros must be valid Rust syntax and must evaluate to a valid Rust AST node. See TLBORM (https://danielkeep.github.io/tlborm/book/index.html)

Idea: Using the ast module, create a system for AST-affecting macros in Python. Macros should be valid Python syntax and manipulate the AST, not the source code. Features, syntax, and implementation are entirely up to you

#

@brisk zenith I think this may be good enough for the challenge repo

snow beacon
#

You've described Hy pretty succinctly.

pure dew
#

ah does that use the ast?

#

ah well, it'd be neat to see yalls impls of this

sick hound
snow beacon
#

That's pretty cool.

#

Nice job.

sick hound
#

thx

gilded orchid
#

challenge (I don't know if this is possible): make it so when you add an int and a tuple, it doesn't error and actually adds the length of the tuple to the int

#

eg:5 + (6, 7, 2) would be 8

zealous widget
#
In [151]: class weird(tuple):
     ...:     def __add__(self, other):
     ...:         return len(self) + other
     ...:         

In [152]: weird((5,6,7)) + 6
Out[152]: 9

caveats here though, weird has to come first

sick hound
#

or just implement a __radd__

zealous widget
#

fair enough

marsh void
#

weird.__radd__ = weird.__add__

#

🤔

#

Why y’all using ` ` if you can escape with backslashes?

sick hound
#

@marsh void because it looks more readable than normal text

marsh void
#

yeah maybe

#

it depends ¯_(ツ)_/¯

zealous widget
#
In [157]: class bro:
     ...:     def __matmul__(self, other):
     ...:         print("bro")
     ...:         

In [158]: dont = bro()

In [159]: me = bro()

In [160]: dont@me
bro
grizzled cloak
#

Hahaha

snow beacon
#

I know I've got a good idea for a Python program when line two is python class String(int):

marsh void
#

lol

#

how about

#

Creating __iter__ and __len__ for int?

#

list(123) -> [1, 2, 3]; len(123) -> 3

snow beacon
#

It's for a devious programming language. (It won't be interpreted, but misinterpreted.) Strings are long curly things, with a length, so it makes sense for their length to be the important feature. That's why they're the numeric type of the language.

#

Bit will represent a bit of text, of course.

#

(The implementation will probably be perfectly normal Python so you won't see much of it in this channel.)

grizzled cloak
#

@gilded orchid

>>> 5 + (1)
6
>>> 5 + (1,2)
7
>>> 5 + (1,2,3)
8
>>>  ```
#

but normal addition still works:

>>> 5+5
10```
snow beacon
#

The first one isn't a tuple, by the way.

grizzled cloak
#

ah

#

guess that shows normal addition still works too

edgy kelp
#

what I'd like to see more is + on tuples creating a new tuple that includes what you try to add, (item, item) + (item,) looks bad 😄

#

imagine that isn't terribly hard to do

grizzled cloak
#

could you elaborate?

edgy kelp
#

say you have a tuple (1, 2) and want to add 3 to it, you have to create a new tuple and then add that in

grizzled cloak
#
>>> (1,2)+3
(1, 2, 3)```
#

like that?

#

this is my new favorite thing to do

edgy kelp
#

yep

snow beacon
#

What happens if you have ```python
((1, 2), (2, 3)) + (4, 5)

grizzled cloak
#
>>> ((1, 2), (2, 3)) + (4, 5)
((1, 2), (2, 3), (4, 5))```
snow beacon
#

So it overrides the original code.

grizzled cloak
#

what should the result be?

edgy kelp
#
>>> ((1, 2), (2, 3)) + (4, 5)
((1, 2), (2, 3), 4, 5)

in a normal environment

formal sandal
#

Maybe you could also do

(1, 2, 3) * 4 == ((1, 4), (2, 4), (3, 4))
grizzled cloak
#

new and improved:

>>> (1,2)+3
(1, 2, 3)
>>> ((1, 2), (2, 3)) + (4, 5)
((1, 2), (2, 3), 4, 5)
>>>    ```
sick hound
#

what if you want to add the tuple to it though

formal sandal
#

((1, 2), (2, 3)) + ((4, 5),) ?

agile crane
#

nice.

#

stupid question: why is the comma required there? i've come across something similar with tuples of length one befor ebut never thought about it much

formal sandal
#

!e

x = (1)
print(type(x), x)
y = (1,)
print(type(y), y)```
night quarryBOT
#

@formal sandal Your eval job has completed with return code 0.

001 | <class 'int'> 1
002 | <class 'tuple'> (1,)
formal sandal
#

Because the ( and ) don't have anything to do with creating a tuple actually.

#

Tuples are created with commas.

edgy kelp
#

just helps to show it is a tuple

agile crane
#

Ah, got it. Makes sense, ty.

edgy kelp
#

the trailing comma may be a bit too inconspicuous

formal sandal
#

!e

x = 1, 2
print(x)
#

arghhhh

sick hound
#
>>> x = 1,
>>> print(x)
(1,)```
gilded orchid
#
>>> 5,7,
(5, 7)
>>> 5,7,,
SyntaxError: invalid syntax
>>> 

challenge: makr it so the second one doesn't error

#

(but has the same result as the first one)

pure dew
#

uh

#

its invalid syntax

#

you'd have to rebuild the parser

gilded orchid
#

oh yeah nvm i'm dumb

gilded orchid
#

challenge: make a code-art quine (so a quine that also works for the code-art challenge)

marsh void
#

lol

#

let’s rebuild the parser anyway

formal sandal
#

@pure dew Did you know that you could multiply transformers in lark-parser?

#

Where can it be useful?

#
# in Transformer class
    def __mul__(self, other):
        return TransformerChain(self, other)
...

class TransformerChain(object):
    def __init__(self, *transformers):
        self.transformers = transformers

    def transform(self, tree):
        for t in self.transformers:
            tree = t.transform(tree)
        return tree

    def __mul__(self, other):
        return TransformerChain(*self.transformers + (other,))
gilded orchid
#

Challenge: make it so built ins like map and range return lists instead of generators

sick hound
#
def map(whatever the actual signature is):
  return builtins.map(whatever the actual signature is)
#
>>> __builtins__.map = (lambda map: lambda *a: list(map(*a)))(__builtins__.map)
>>> __builtins__.range = (lambda range: lambda *a: list(range(*a)))(__builtins__.range)
>>> map(int, '12345')
[1, 2, 3, 4, 5]
>>> range(3, 10)
[3, 4, 5, 6, 7, 8, 9]```
gilded orchid
#

Challenge: make it so any error (in a REPL, not including syntax errors) doesn't get outputted

edgy kelp
#

uhh

>>> import sys
>>> def hook(*_): pass
...
>>> sys.excepthook = hook
>>> raise ValueError
>>> raise BaseException
sick hound
#
>>> import sys
>>> sys.excepthook = lambda *a: None
>>> 1/0
>>> raise BaseException
>>> )
>>>``` this kind of works but it includes syntax errors too
edgy kelp
#

could just use some handling for syntaxerrors but that's not something horribly difficult

drowsy cobalt
#

anyone know a better way of achieving this?

#
# i would like mapping to map from items' index to a customized no-arg function
mapping = {}
my_items = [1, 4, 21, 19]

def do_a_thing(item):
    print("I am doing stuff for", item)

for index, item in enumerate(my_items):
    # bind n to i early in the function parameters
    def custom_func(n=item):
        do_a_thing(n)
    mapping[index] = custom_func

mapping[2]()

# this don't work :(
#for index, item in enumerate(my_items):
#    mapping[index] = lambda: do_a_thing(item)
sick hound
#

instead of py def custom_func(n=item): do_a_thing(n) mapping[index] = custom_func you could do py mapping[index] = (lambda n: lambda: do_a_thing(n))(item)

#

i'm not sure if that's better but it's more esoteric and you did ask in #esoteric-python :P

drowsy cobalt
#

maybe wrong channel, but yeah I guess I was looking for a less esoteric looking way

#

anything that doesn't look like a hack until you stare at it for 30 seconds, 5cm away from your monitor

#

ok I guess partial is a way

#

mapping[index] = partial(do_a_thing, item)

sick hound
#

oh yeah that works

drowsy cobalt
#

clever lambda'ing though 😖

marsh void
#

lambda is cool

gilded orchid
#

Lambda > Functions

#

Short-circuiting > If statements

edgy kelp
#

functions > functions

wind maple
#

🤔

pure dew
#

expressions > statements

wind maple
#

numbers > numerals

gilded orchid
#

Lambda arguments > variables

#

One line > more than one line

#

Abusing ctypes and getting seg faults > anything else

#

What's the shortest way to decrement every item in a list?

edgy kelp
#

numpy? 😛

gilded orchid
#

I don't think that'd be shorter than the obvious map

#

If you include the import

edgy kelp
#

so guessing not in place when you're going with map

gilded orchid
#

Actually I think list comps would be shorter

#

[x-1 for x in l]

pure dew
#

Shorter: [x-1for x in l]

marsh void
#

yes but why

pure dew
#

code golf

grave rover
#

Does anyone know of a way to make a < b < c automatically behave like (a < b) < c instead of (a < b) and (b < c)?

zealous widget
#

True\False < c ?

#

i guess that works, they are ints

grave rover
#

Context: I'm working on implementing generics: ```py
if name == "main":
@generic("A", "B")
class Pair:
x: "A"
y: "B"

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __iter__(self):
        return iter([self.x, self.y])

p = Pair<(int, int)>(10, 5)

```but above here it's comparing Pair < (int, int) but also (int, int) > (10, 5) instead of using the custom class the former returns

grave rover
#
    p1 = Pair[int, int](10, 5)
    p2 = Pair[int, str](100, "abc")

    print(p1.__annotations__)
    print(list(p1))

    print(p2.__annotations__)
    print(list(p2))

# == output ==
{'x': <class 'int'>, 'y': <class 'int'>}
[10, 5]
{'x': <class 'int'>, 'y': <class 'str'>}
[100, 'abc']
```here's the end result, not as clean as I'd hoped but it works
pure dew
#

generics in a non-strict language

#

looks neat tho

grave rover
#

I mean

#

I can combine this with my function overloading library to enforce types smug2

#

if only there was a way to apply a decorator to all functions

pure dew
#

also you can omit the parens there

#

Pair<int, int>(5, 6)

#

PRust :D

grizzled cloak
#

@grave rover you can in classes

grave rover
#

that'll eval as (Pair<int), (int>(5,6)) @pure dew

grizzled cloak
#

Using getatr I think.

grave rover
#

@grizzled cloak how so

#

nope

grizzled cloak
#

Why?

#

It gets called with every method

grave rover
#

because of equality order

#

it's an optimization python does

#

actually

#

it's just the chaining

#

a < b < c makes sense to be a < b && b < c

#

so thats what it does internally

grizzled cloak
#

Try that

grave rover
#

oh you mean that

#

doesnt work on normal funcs

grizzled cloak
#

Yeah on classes

grave rover
#

I basically want to override behavior or function.__new__

grizzled cloak
#

Ah!

grave rover
#

or wrap all functions with that

grizzled cloak
#

One sec

grave rover
#

I can't curse the method because of how cpython internals work

pure dew
#

oh i see

#

real shame, cus i like <type, type> better

grave rover
#

same

grizzled cloak
#

@grave rover why cant you?

grave rover
#

lets think about this