Hogyan állítsuk össze a Python absztrakt szintaxis fákat (AST) a Mathematicában?

Szeretném összeállítani a Python “ ast.Module “objektumokat a Mathematica belsejében, majd pl ExternalEvaluate["exec(astObject)"].

A Python ast , parse , eval , exec és compile függvények mind működhetnek a “ ast.Module “objektumokat, akár kiírja őket, akár bemenetként veszi őket. Azonban nem tudom, hogyan állítsam össze ezt a astObject a Mathematica / WL-ben. majd elküldöm a Pythonnak a ExternalEvaluate keresztül.

Megpróbálok programszerűen generálni Python kódot MMA-ban (genetikai algoritmushoz), majd elküldeni a Pythonnak Össze tudtam állítani Python-kód karaktersorozatokat, de akkor az összes behúzást kezelnem kell, ami fájdalomnak tűnik.

Például a Pythonban a következőket teheti meg:

import ast pythonString="X3=X1*X2" astObject=ast.parse(pythonString) X1=3 X2=4 exec(compile(astObject,"","exec")) print(X3) -> 12 

És természetesen az MMA-ból lehetséges:

session=StartExternalSession["Python"] ExternalEvaluate[session, {"import ast","X1=3","X2=4", "exec(compile(ast.parse(\"X3=X1*X2\"),\"\",\"exec\"))"} ] 

ugyanazt eredményezni eredmény (azaz 12).

Viszont szeretném létrehozni a Python kód bitjeimet ("X1=3", "X2=4", "X3=X1*X2") a Mathematicában. Ezek a bitek itt elég egyszerűek, de teljes programokat, azaz utasításokat és kifejezéseket szándékozom metaprogrammatikusan generálni (!). Ehhez aztán kitalálni, hogyan kell elemezni a Python bosszantó behúzásait, ami természetesen megkülönbözteti az egyik kifejezést a másiktól, és milyen függőségeik vannak. Nem szívesen teszem ezt, és arra gondoltam, hogy talán könnyebb működtetni az ast struktúrát.

Eredetileg azt gondoltam, hogy képes lennék használni egy köztes karakterlánc-formát a Python “s ast.dump() függvényéből, amely a következőképpen néz ki:

astString = ast.dump(pythonString) -> "Module(Body=[Assign(targets=[Name(id="X3",ctx=Store())],value=BinOp(left=Name(id="X1", ctx=Load()),op=Mult(),right=Name(id="X2",ctx=Load())))])" 

és mivel ez astString lényegében sorosítja a astObject -et. Ezt én is előállíthatnám. Azonban nem találok semmilyen módot arra, hogy a Python bármit is csináljon ezzel az astString.

Létrehozható egy ilyen Python-objektum – például a fenti astObject – a Mathematica oldalon?

B

PS: Itt található az “ ast.Module ” objektumok leírása: https://greentreesnakes.readthedocs.io/en/latest/tofrom.html

PPS: Ezt keresztbe tettem a Wolfram közösségbe: https://community.wolfram.com/groups/-/m/t/2070851

Megjegyzések

  • ” Ehhez ki kell derítenem, hogyan kell értelmezni a Python ‘ s idegesítő behúzásokat […] ” – Tudom, hogy az AST használatát kéri, de talán a Python ‘ s behúzásokkal foglalkozó válaszok is érdeklik.
  • Igen, Anton, igazad van, én is tisztán húr alapú megoldásokat vizsgálok. És ezek mentén néztem a FunctionalParsers.m csomagot, mint a Python ‘ nyelvtan nyelvű automatikus importálásának módját, hogy talán lehetővé tegyem az ál-Python-explicit-zárójelezés generálását. , vagy esetleg Hy kód létrehozására (amely a Pyp-ben írt Lisp), amelynek természetesen megfelelő a zárójelezése. Csak nem tudom ‘ megérteni, hogy valaki miért hozna létre nyelvet behúzás alapján, vagy miért folytatná más ‘ s ezt használni …
  • ” egyszerűen nem tudom megérteni ‘, hogy miért hozna létre valaki nyelvet behúzás alapján, vagy miért más ‘ ek folytatnák a használatát … Ez sok embert misztifikál!
  • A ” FunctionalParsers.m ” használata érdekes ötlet, de ennek megvalósítása lehet, hogy korántsem olyan egyszerű vállalkozás …
  • Lehet, hogy jobban jársz, ha két szoftvermonádot programozol, egyet WL-ben, másikat Python-ban, amelyek ugyanolyan munkafolyamat-tervezéssel rendelkeznek. Ezután kisebb kódváltásokkal átkerül köztük; szintén nincs szükség speciális formázásra a Python számára. Itt van egy példa egy LSAMon nevű monáddal. (Görgessen az aljára.)

Válasz

Nem vagyok biztos benne, hogy pontosan mit keres. Azt hiszem, a kérdésedre adott válasz:

Programozatosan próbálok Python kódot generálni az MMA-ban […], majd nyújtsa be a Pythonnak értékelésre. Össze tudtam állítani a Python kód karaktersorozatait, de akkor az összes behúzást kezelnem kell, ami fájdalomnak tűnik.

Lehetséges ilyen Python objektum létrehozása a Mathematica oldalon?

A

a ExternalEvaluate és a Python “s ” ast ” könyvtár.

Íme egy példa:

code = ""[i**2 for i in range(10)]""; astTemplate = StringTemplate["import ast; eval(compile(ast.parse(`1`, mode="eval"), "", "eval"))"]; astTemplate[code] (* "import ast; eval(compile(ast.parse("[i**2 for i in range(10)]", mode="eval"), "", "eval"))" *) ExternalEvaluate["Python", astTemplate[code]] (* {0, 1, 4, 9, 16, 25, 36, 49, 64, 81} *) 

(eval a exec helyett, mert a eval értéket ad vissza.)

Megjegyzések

  • Köszönöm Anton. Igen, tisztább tudtam volna lenni. Hadd frissítsem egy kicsit a kérdésemet. Alapvetően a ” ‘ [i ** 2 i-re a (10) tartományban] ‘ ” rész a válaszodban az MMA-oldalon, de nem Python-karakterláncként, hanem mint ast.Module objektum, amely csatlakoztatható a fordításhoz, az eval és az exec végrehajtásához.

Válasz

Úgy gondolom, hogy a Python kód karaktersorozatként való összeállítása valójában egyszerűbb, mint amit javasol. De azt is tudom, hogy én csak azt mondtam, hogy ez nem fog meggyőzni senkit, ezért itt van egy példa.

Meghatározunk pár szimbolikus fejet, amelyek a Mathematica Python programját fogják képviselni, és egy funkciót, amellyel kifejezések azokkal a szimbolikus fejekkel:

ToPythonString[statements_List] := StringRiffle[ToPythonString /@ statements, "\n"] ToPythonString[PyBlock[statement_, children_, indent_ : 0]] := StringJoin[ StringRepeat[" ", indent], statement, ":\n", ToPythonString[PyIndent /@ children] ] ToPythonString[PyStatement[statement_, indent_ : 0]] := StringJoin[ StringRepeat[" ", indent], statement ] PyIndent[PyBlock[statement_, children_, indent_ : 0]] := PyBlock[ statement, PyIndent /@ children, indent + 1 ] PyIndent[PyStatement[statement_, indent_ : 0]] := PyStatement[ statement, indent + 1 ] 

Amit ezek a funkciók lehetővé tesznek számunkra, az az, hogy Python-kódot írunk a Mathematicába anélkül, hogy gondolkodnánk a behúzáson, ez kicsit olyan, mint Python kód felépítése az ast modullal.

Ez a példa a szimbolikus kifejezés karakterláncként történő megjelenítésére:

prog = { PyStatement["a = 1"], PyStatement["b = 2"], PyBlock["If a > b", { PyStatement["Print("a is larger than b")"] }], PyBlock["def f(x)", { PyStatement["Print("executing f")"], PyBlock["if x > 0", { PyStatement["Print("x is larger than 0")"] }] }] }; ToPythonString[prog] 

Out:

a = 1 b = 2 If a > b: Print("a is larger than b") def f(x): Print("executing f") if x > 0: Print("x is larger than 0") 

Erre könnyen építhetünk, és leíróbbá tehetjük a Python program szimbolikus ábrázolását.

PyAssign[lhs_, rhs_] := PyStatement[lhs <> " = " <> rhs] PyPrint[text_] := PyStatement["Print(" <> text <> ")"] PyFunction[name_, args_, statements_] := PyBlock[ "def " <> name <> "(" <> StringRiffle[args, ", "] <> ")", statements ] PyIf[cond_, statements_] := PyBlock[ "If " <> cond, statements ] PyIf[cond_, statements_, elseStatements_] := { PyBlock[ "If " <> cond, statements ], PyBlock[ "else", elseStatements ] } 

Ezekkel a segítődefiníciókkal most nagyon olvasható stílusban írhatjuk a következő programot.

prog = { PyAssign["a", "1"], PyAssign["b", "2"], PyIf[ "a > b", { PyPrint["a is larger than b"] }], PyFunction["f", {"x"}, PyIf[ "x > 0", {PyPrint["x is larger than 0"]}, {PyPrint["x is not larger than 0"]} ] ] }; ToPythonString[prog] 

Out:

a = 1 b = 2 If a > b: Print(a is larger than b) def f(x): If x > 0: Print(x is larger than 0) else: Print(x is not larger than 0) 

Ha még nincs “”, kérjük, keresse meg ” szimbolikus C a Mathematica dokumentációjában. Ez alapvetően egy AST létrehozásának módja egy C nyelvprogram számára a Mathematicában, amelyet aztán futtatható C kódgá lehet alakítani. Alapvetően itt tartunk ezzel a kóddal is, bár ha egy teljes megvalósítást szándékoznék megvalósítani, akkor ez nem pontosan így nézne ki (az ast modult mindenképpen érdemes tanulmányozni, ha valaki az útvonalon akar menni).

Visszatérve a lényegre: amit ezzel a válasszal szeretnék közölni, az az, hogy nem kell sok időt töltenie egy olyan kis keretrendszer felépítéséhez, amely többé-kevésbé megoldja a kérdésében megemlített behúzási problémát .

Megjegyzések

  • Igen, CE ez nagyon úgy néz ki, hogy amit elképzeltem, kínzást jelentene, és igazad van, ezt megcsináltad egészen egyértelmű. Ilyen módon folytatnom kell a nyelv lefelé terjesztését a levelek felé az atomok és operátorok, listák és tömbök és hasonlók lefedésére, de ez a keret kezeli az összes behúzást, és megvalósíthatónak kell lennie.
  • @berniethejet Ebben a példában meghatároztam például az PyIf -t valamire, ami mássá értékelhető. Fontolja meg, hogy ehelyett hozzáadja a definíciót a ToPythonString elemhez, azaz ToPythonString[PyIf[...]] :=. Így a teljes programját szimbolikus formában vizsgálhatja meg, anélkül, hogy kiértékelné, amíg meg nem hívja a ToPythonString hívást.
  • Köszönöm, ezt jó tudni. A keretrendszere minden bizonnyal jobb, mint bármi más, amit összefogtam volna (morogtam az egész utat, ahogy óhatatlanul is, idegesítem Guido ‘ s behúzási keresztes hadjáratán).

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük